DB aplikacije

SQL v aplikacijski kodi
Iztok Savnik, FAMNIT
OPB, SQL&Aplikacije
Pregled
• SQL v aplikacijski kodi
• Vgnezden SQL
• Kursorji
• Dinamični SQL
• JDBC
• SQLJ
• Shranjene procedure
OPB, SQL&Aplikacije
SQL v aplikacijski kodi
SQL ukazi se lahko prožijo iz programa napisanega v
splošnem programskem jeziku (C++ | Java).
• SQL stavki lahko uporabljajo spremenljivke jezika gostitelja.
• Vsebujejo tudi stavke za priklop na podatkovno bazo.
Obstajata dva glavna pristopa k integraciji:
• Vgnezden SQL v gostiteljskem programskem jeziku (Embedded
SQL, SQLJ)
• Kreacija posebnega API za klicanje SQL ukazov (JDBC)
OPB, SQL&Aplikacije
SQL v aplikacijski kodi (nadal.)
Problem impedance:
• SQL relacije so (multi-) množice zapisov, ki nimajo
določenega maksimalnega št. zapisov.
• Običajno nimamo takšne podatkovne strukture v
klasičnih proceduralnih programskih jezikih (imamo
sicer knjižnice, npr. STL).
• SQL podpira mehanizem kurzorjev za delo z
relacijami.
OPB, SQL&Aplikacije
Vgnezden SQL
Pristop:
Vgnezdi SQL stavke v gostiteljski jezik.
Pred-procesor prevede SQL stavke v posebne API klice.
Potem uporabimo običajen prevajalnik za prevajanje kode .
Gradniki jezika:
Priklučitev na SUPB:
EXEC SQL CONNECT
Deklaracija vrednosti:
EXEC SQL BEGIN (END) DECLARE SECTION
Stavki:
EXEC SQL Statement;
OPB, SQL&Aplikacije
Vgnezden SQL: Spremenljivke
EXEC SQL BEGIN DECLARE SECTION
char c_sname[20];
long c_sid;
short c_rating;
float c_age;
EXEC SQL END DECLARE SECTION
Two special “error” variables:
SQLCODE (long, is negative if an error has occurred)
SQLSTATE (char[6], predefined codes for common errors)
OPB, SQL&Aplikacije
Kurzorji
Definiramo lahko kurzor na relaciji ali poizvedbi (ki
generira relacijo).
Lahko odpremo kurzor, preberemo n-terico in potem
premaknemo kurzor naprej za eno mesto. Potem spet
preberemo n-terico...
Vrstni red n-teric v relaciji, ki jo beremo je določen z SQL
vprašanjem.
Lahko tudi spremenimo ali izbrišemo zapis na
katerega kaže kurzor.
OPB, SQL&Aplikacije
Primer: Kurzor, ki poišče imena mornarjev, ki so
rezervirali rdečo ladjo, v abecednem vrstnem
redu
EXEC SQL DECLARE sinfo CURSOR FOR
SELECT S.sname
FROM Sailors S, Boats B, Reserves R
WHERE S.sid=R.sid AND R.bid=B.bid AND B.color=‘red’
ORDER BY S.sname
OPB, SQL&Aplikacije
SQL vgnezden v C: Primer
char SQLSTATE[6];
EXEC SQL BEGIN DECLARE SECTION
char c_sname[20]; short c_minrating; float c_age;
EXEC SQL END DECLARE SECTION
c_minrating = random();
EXEC SQL DECLARE sinfo CURSOR FOR
SELECT S.sname, S.age
FROM Sailors S
WHERE S.rating > :c_minrating
ORDER BY S.sname;
do {
EXEC SQL FETCH sinfo INTO :c_sname, :c_age;
printf(“%s is %d years old\n”, c_sname, c_age);
} while (SQLSTATE != ‘02000’);
EXEC SQL CLOSE sinfo;
OPB, SQL&Aplikacije
Dinamični SQL
SQL vprašanja so znana v času prevajanja.
Dinamični SQL omogoča konstrukcijo SQL stavkov
on-the-fly.
Primer:
char c_sqlstring[]=
{“DELETE FROM Sailors WHERE raiting>5”};
EXEC SQL PREPARE readytogo FROM :c_sqlstring;
EXEC SQL EXECUTE readytogo;
OPB, SQL&Aplikacije
Omejitve statičnega SQL
• Delo z kurzorji je statično zakodirano v
programu
– Spremenljivke lahko uporabimo za parametre SQL
vprašanja
exec sql select name, quota, sales
from salesreps
where quota > :cutoff_amount;
exec sql update salesreps
set quota = quota + :increase
where quota > :cutoff_amount;
OPB, SQL&Aplikacije
Omejitve statičnega SQL
• Ne moremo pa spreminjati imen tabel in
stolpcev
– Poskus izvajanja vrne napako
exec sql update :which_table
set :which_column = 0;
exec sql declare cursor cursor7 for
select *
from :which_table;
• Spremeni se lahko rezultat
– Stolpci v tabeli, ki je rezultat poizvedbe se
spremenijo
OPB, SQL&Aplikacije
Osnove dinamičnega SQL
• Ne zakodiraj SQL stavka v program gostitelja
– Omogoči gradnjo SQL stavka v programu
• Nekatere enostavne ideje se zakomplicirajo
• Izvajanje SQL iz stališča prevajalnika
– Statični SQL
• V času prevajanja se določi program (opt) SQL stavka
• V času izvajanja se samo interpretira
– Dinamični SQL
• SQL stavek ni znan do izvajanja
• Program SQL stavka se določi v času izvajanja
• SQL se lahko izgradi v programu gostitelja
OPB, SQL&Aplikacije
OPB, SQL&Aplikacije
Komentarji
• SQL stavki implementirani z dinamičnim SQL se
izvajajo počasneje
• Večina programerjev ne uporablja dinamičnega
SQL ker ni potrebe
• Aplikacije klient/strežnik velikokrat zahtevajo
uporabo dinamičnega SQL
OPB, SQL&Aplikacije
1) Takojšnje izvajanje SQL
• Najenostavnejši način je takojšnje izvajanje
SQL stavka iz niza znakov
– EXECUTE IMMEDIATE
• Koraki:
– Program konstruira SQL stavek. SQL stavek ne
sme vračati vrednosti !
– Program pošlje SQL stavek z EXECUTE
IMMEDIATE SQL strežniku
– SQL stavek se izvede na SQL strežniku
OPB, SQL&Aplikacije
Zgled:
OPB, SQL&Aplikacije
Zgled:
• Izvajanje programa
Enter table name: staff
Enter search condition: quota < 20000
Delete from staff successful.
• Stavek, ki se je izvajal
delete from staff
where quota < 20000
• Stavki SQL: DELETE, INSERT, UPDATE, COMMIT
OPB, SQL&Aplikacije
2) Dinamično izvajanje
• Dinamični SQL se izvaja hitreje od EXECUTE
IMMEDIATE
• Z dinamičnim SQL izvajamo stavke, ki jih
generira uporabnik in se izvajajo zelo
velikokrat
• Koraki izvajanja
1) Program pripravi SQL stavek. Vprašaj »?« se
vstavi na mesto kjer se pričakuje spremenljivke.
Vprašaj imenujemo vrzel.
2) Stavek PREPARE zahteva od strežnika, da
razčeni, preveri in optimizira SQL stavek. Rezultat
je plan izvajanja SQL stavka. SQL strežnik postavi
SQLCODE/SQLSTATE.
OPB, SQL&Aplikacije
2) Dinamično izvajanje
• Koraki izvajanja
3) Ko program želi izvajati pripravljeni SQL stavek
naredi to ukazom EXECUTE s katerim se prenesejo
tudi parametri. SQL strežnik postavi parametre SQL
stavka in izvaja prej pripravljen plan.
4) Program lahko izvaja stavek EXECUTE večkrat s
spremenjenimi parametri.
OPB, SQL&Aplikacije
Zgled
• Splošen program za izvajanje stavka UPDATE
• Začetni stavek (niz znakov)
update table-name
set second-column-name = ?
where first-column-name = ?
• Uporabnik določi parametre pred izvajanjem
SQL stavka
OPB, SQL&Aplikacije
Zgled:
OPB, SQL&Aplikacije
Zgled:
OPB, SQL&Aplikacije
Zgled: primer izvajanja
OPB, SQL&Aplikacije
API alternativa
Namesto da bi spreminjali prevajalnik raje dodamo
knjižnico za delo z podatkovno bazo (API).
• Poseben standardiziran vmesnik: procedure/objekti.
• Podamo SQL niz iz jezika SQL stežniku in predstavi rezultate
vprašanja v obliki prijazni do jezika.
• Sun JDBC: Java API
• Gonilnik neodvisen od SUPB ujame klice in jih prevede v
DBMS-specifično kodo; podatkovna baza je lahko nekje v mreži.
OPB, SQL&Aplikacije
JDBC Arhitektura
Štiri arhitekturne komponente:
• Aplikacija: inicira in zakluči povezavo (connection), pošlje SQL
stavke stežniku.
• Upravljalnik gonilnika: nalaganje JDBC gonilnika
• Gonilnik: poveže se na podatkovni vir, prenaša zahteve ter
vrača in prevaja rezultate poizvedb ter kode napak.
• Podatkovni vir: preprocesira SQL stavke
OPB, SQL&Aplikacije
JDBC Arhitektura (nadal.)
Štiri vrste gonilnika:
Direktno prevajanje v domač API pod.vira, gonilnik ni v Javi:
Prevede SQL ukaze v domač API od podatkovnega vira. Potrebuje OS-specifičeno binarno
kodo na vsakem klientu.
Prevajanje v domač API preko Java gonilnika:
Prevede JDBC klice direktno v omrežni protokol, ki ga uporablja SUPB. Potrebuje Java
gonilnik za specifičen SUPB na vsakem klientut.
Most (Bridge):
Prevede SQL ukaze v tuj API. Primer: JDBC-ODBC most. Koda za ODBC in JDBC
gonilnik morata biti na klientu.
Omrežni most (Network bridge):
Pošilja ukaze prek omrežja vmesni opremi (middleware), ki komunicira s podatkovnim
virom. Potrebuje majhen JDBC gonilnik na vsakem klentu.
OPB, SQL&Aplikacije
JDBC razredi in vmesniki
Koraki pri pošiljanju poizvedbe nad podatkovno
bazo:
• Naloži JDBC gonilnik
• Povezovanje s podatkovnim virom
• Izvajaj SQL stavke
OPB, SQL&Aplikacije
Upravljanje JDBC gonilnika
• Vse gonilnike upravlja razred DriverManager
• Nalaganje JDBC gonilnika:
v Java kodi:
Class.forName(“oracle/jdbc.driver.Oracledriver”);
Ob startu Java aplikacije:
Djdbc.drivers=<oracle/jdbc.driver
OPB, SQL&Aplikacije
Povezave z JDBC
S podatkovnim virom delamo preko seje (session). Vsaka
povezava identificira logično sejo:
•
JDBC URL:
jdbc:<subprotocol>:<otherParameters>
Primer:
String url=“jdbc:oracle:www.bookstore.com:3083”;
Connection con;
try{
con = DriverManager.getConnection(url,usedId,password);
} catch SQLException excpt { ...}
OPB, SQL&Aplikacije
Vmesnik razreda Connection
• Postavi izolacijski nivo trenutne povazave s podatkovno bazo.
public int getTransactionIsolation()
void setTransactionIsolation(int level)
• Specificira če so transakcije v dani povezavi samo-bralne.
public boolean getReadOnly()
void setReadOnly(boolean b)
• Če je postavljen autocommit potem se vsak SQL stavek smatra
transakcija.
• Sicer se transakcija zaključi s commit(), ter prekine z rollback().
public boolean getAutoCommit() and void setAutoCommit(boolean b)
• Preveri ali je povezava še odprta.
public boolean isClosed()
OPB, SQL&Aplikacije
Izvajanje SQL stavkov
Imamo tri različne načine za izvajanje SQL stavkov:
Statement (statični in dinamični SQL stavki)
PreparedStatement (semi-statični SQL stavki)
CallableStatment (shranjene procedure)
Razred PreparedStatement:
Vnaprej prevedeni, parametrizirani SQL stavki:
Struktura je fiksna.
Vrednosti parametrov so določene v času izvajanja.
OPB, SQL&Aplikacije
Izvajanje SQL stavkov (nadal.)
String sql=“INSERT INTO Sailors VALUES(?,?,?,?)”;
PreparedStatment pstmt=con.prepareStatement(sql);
pstmt.clearParameters();
pstmt.setInt(1,sid);
pstmt.setString(2,sname);
pstmt.setInt(3, rating);
pstmt.setFloat(4,age);
// we know that no rows are returned, thus we use executeUpdate()
int numRows = pstmt.executeUpdate();
OPB, SQL&Aplikacije
ResultSets
PreparedStatement.executeUpdate vrne število
spremenjenih zapisov.
• PreparedStatement.executeQuery vrne podatke, ki
so shranjeni v objektu ResultSet (ki je kurzor)
•
ResultSet rs=pstmt.executeQuery(sql);
// rs is now a cursor
While (rs.next()) {
// process the data
}
OPB, SQL&Aplikacije
ResultSets (nadaljevanje)
ResultSet je zelo izrazen kurzor:
• previous(): premakne se eno vrstico nazaj
• absolute(int num): premakne na vrstico z
določeno številko
• relative (int num): premakne se naprej ali nazaj
• first() in last()
OPB, SQL&Aplikacije
Ujemanje Java in SQL tipov
SQL Type
Java class
ResultSet get method
BIT
CHAR
VARCHAR
DOUBLE
FLOAT
INTEGER
REAL
DATE
TIME
TIMESTAMP
Boolean
String
String
Double
Double
Integer
Double
java.sql.Date
java.sql.Time
java.sql.TimeStamp
getBoolean()
getString()
getString()
getDouble()
getDouble()
getInt()
getFloat()
getDate()
getTime()
getTimestamp()
OPB, SQL&Aplikacije
JDBC: Izjeme in opozorila
Večino java.sql vrže SQLException če se pojavi
napaka.
SQLWarning je podrazred SQLException;
ni tako resna napaka (obstoj moramo testirat
eksplicitno)
OPB, SQL&Aplikacije
Opozorila in izjeme (nadal.)
try {
stmt=con.createStatement();
warning=con.getWarnings();
while(warning != null) {
// handle SQLWarnings;
warning = warning.getNextWarning():
}
con.clearWarnings();
stmt.executeUpdate(queryString);
warning = con.getWarnings();
...
} //end try
catch( SQLException SQLe) {
// handle the exception
}
OPB, SQL&Aplikacije
Meta podatkovna baza
Objekt DatabaseMetaData vsebuje podatke o sistemu
za delo s podatkovno bazo in katalog.
DatabaseMetaData md = con.getMetaData();
// print information about the driver:
System.out.println(
“Name:” + md.getDriverName() +
“version: ” + md.getDriverVersion());
OPB, SQL&Aplikacije
Meta podatkovna baza (nadal.)
DatabaseMetaData md=con.getMetaData();
ResultSet trs=md.getTables(null,null,null,null);
String tableName;
While(trs.next()) {
tableName = trs.getString(“TABLE_NAME”);
System.out.println(“Table: “ + tableName);
//print all attributes
ResultSet crs = md.getColumns(null,null,tableName, null);
while (crs.next()) {
System.out.println(crs.getString(“COLUMN_NAME” + “, “);
}
}
OPB, SQL&Aplikacije
(ne-) Kompleten primer
Connection con = // connect
DriverManager.getConnection(url, ”login", ”pass");
Statement stmt = con.createStatement(); // set up stmt
String query = "SELECT name, rating FROM Sailors";
ResultSet rs = stmt.executeQuery(query);
try { // handle exceptions
// loop through result tuples
while (rs.next()) {
String s = rs.getString(“name");
Int n = rs.getFloat(“rating");
System.out.println(s + " " + n);
}
} catch(SQLException ex) {
System.out.println(ex.getMessage ()
+ ex.getSQLState () + ex.getErrorCode ());
}
OPB, SQL&Aplikacije
SQLJ
• Komplementira JDBC s (semi-)statičnim modelom vprašanja:
• Prevajalnik preveri sintakso, preveri tipe, konsistenco poizvedbe s
shemo, ....
• Vsi argumenti so vedno povezani z isto spremenljivko:
#sql = {
SELECT name, rating INTO :name, :rating
FROM Books WHERE sid = :sid;
• Primerjaj z JDBC:
sid=rs.getInt(1);
if (sid==1) {sname=rs.getString(2);}
else { sname2=rs.getString(2);}
• SQLJ (del SQL standarda) proti vgnezdenem SQL (specifičen)
OPB, SQL&Aplikacije
SQLJ koda
Int sid; String name; Int rating;
// named iterator
#sql iterator Sailors(Int sid, String name, Int rating);
Sailors sailors;
// assume that the application sets rating
#sailors = {
SELECT sid, sname INTO :sid, :name
FROM Sailors WHERE rating = :rating
};
// retrieve results
while (sailors.next()) {
System.out.println(sailors.sid + “ “ + sailors.sname));
}
sailors.close();
OPB, SQL&Aplikacije
SQLJ iteratorji
Dva tipa iteratorjev (“kurzorjev”):
• Imenovan iterator
Potrebuje ime in tip spemenljivke; omogoča branje stolpcev po imenu.
Poglej primer na prejšnji prosojnici.
• Pozicijski iterator
Potrebuje samo tip spremenljivke; nato uporablja konstrukt FETCH .. INTO:
#sql iterator Sailors(Int, String, Int);
Sailors sailors;
#sailors = ...
while (true) {
#sql {FETCH :sailors INTO :sid, :name} ;
if (sailors.endFetch()) { break; }
// process the sailor
}
OPB, SQL&Aplikacije
Shranjene procedure
Kaj so shranjene procedure:
Program, ki se izvaja preko enega samega SQL stavka
Izvaja se kot proces na strežniku
Prednosti:
Lahko vgradimo aplikacijsko logiko in ostanemo blizu
podatkov.
Možna ponovna uporaba aplikacijske logike, različni
uporabniki.
Izognemo se vračanju zapis-po-zapis preko kursorja.
OPB, SQL&Aplikacije
Shranjene procedure: Primeri
CREATE PROCEDURE ShowNumReservations
SELECT S.sid, S.sname, COUNT(*)
FROM Sailors S, Reserves R
WHERE S.sid = R.sid
GROUP BY S.sid, S.sname
Shranjene procedure imajo lahko parametre:
Tri različne načini: IN, OUT, INOUT
CREATE PROCEDURE IncreaseRating(
IN sailor_sid INTEGER, IN increase INTEGER)
UPDATE Sailors
SET rating = rating + increase
WHERE sid = sailor_sid
OPB, SQL&Aplikacije
Shranjene procedure: Primeri
Shranjene procedure so lahko napisane v drugih
programskih jezikih, ne nujno v SQL:
CREATE PROCEDURE TopSailors( IN num INTEGER)
LANGUAGE JAVA
EXTERNAL NAME “file:///c:/storedProcs/rank.jar”
OPB, SQL&Aplikacije
Klicanje shranjenih procedur
EXEC SQL BEGIN DECLARE SECTION
Int sid;
Int rating;
EXEC SQL END DECLARE SECTION
// now increase the rating of this sailor
EXEC CALL IncreaseRating(:sid,:rating);
OPB, SQL&Aplikacije
Klicanje shranjenih procedur
JDBC:
SQLJ:
CallableStatement cstmt=
con.prepareCall(“{call
ShowSailors});
ResultSet rs =
cstmt.executeQuery();
while (rs.next()) {
...
}
#sql iterator
ShowSailors(...);
ShowSailors showsailors;
#sql showsailors={CALL
ShowSailors};
while (showsailors.next()) {
…
}
OPB, SQL&Aplikacije
SQL/PSM
• Večina DBMS omogoča uporabnikom pisanje shranjenih
procedur v visoko-nivojskem programskem jeziku (blizu
SQL).
• SQL/PSM - Persistent Stored Modules, SQL/Foundations
Deklariraj shranjeno proceduro:
CREATE PROCEDURE name(p1, p2, ..., pn)
local variable declarations
procedure code;
Deklariraj funkcijo:
CREATE FUNCTION name (p1, ..., pn) RETURNS
sqlDataType
local variable declarations
function code;
OPB, SQL&Aplikacije
Osnovni SQL/PSM gradniki
CREATE FUNCTION rateSailor
(IN sailorId INTEGER)
RETURNS INTEGER
DECLARE rating INTEGER
DECLARE numRes INTEGER
SET numRes = (SELECT COUNT(*)
FROM Reserves R
WHERE R.sid = sailorId)
IF (numRes > 10) THEN rating =1;
ELSE rating = 0;
END IF;
RETURN rating;
OPB, SQL&Aplikacije
Osnovni SQL/PSM gradniki
•
•
•
•
Lokalne spremenljivke (DECLARE)
RETURN vrednosti za FUNCTION
Prirejanje vrednosti spremenljivkam SET
Vejitve in zanke:
IF (condition) THEN statements;
ELSEIF (condition) statements;
... ELSE statements; END IF;
LOOP statements; END LOOP
• Poizvedbe so deli izrazov.
• Lahko uporabljamo kurzorje naravno brez “EXEC SQL”
OPB, SQL&Aplikacije
Povzetek
• Vgnezdeni SQL dovoljuje izvajanje parametričnih
statičnih poizvedb v gotiteljskem jeziku.
• Dinamični SQL dovoljuje izvajanje ad-hoc poizvedb iz
gostiteljskega jezika.
• Mehanizem kurzorjev omogoča branje enega zapisa
naenkrat in premosti impedančni problem med
gostiteljem in SQL.
• API kot npr. JDBC implementira plast abstrakcije med
aplikacijo in DBMS.
OPB, SQL&Aplikacije
Povzetek (nadal.)
• SQLJ: Statični model, poizvedbe se preverijo v
času prevajanja.
• Shranjene procedure izvajajo aplikacijsko
logiko direktno na strežniku.
• SQL/PSM standard za pisanje shranjenih
procedur.
OPB, SQL&Aplikacije