Mivel a JDBC adatbázisfüggetlen API, ezért tudnia
kell kezelni az adatbáziskezelő rendszerek SQL megvalósításai közötti apró
különbségeket is. Ezen probléma megoldására a JDBC három módszert is biztosít:
-
akármilyen szöveges utasítás (tehát nemcsak SQL utasítások!) átadható az
adatbázisnak. Igy egy adott adatbázistípus esetén maximálisan ki lehet
használni annak minden specifikus lehetőségeit is. A módszer hátránya,
hogy a program elveszti hordozhatóságát, mivel nem biztos, hogy más
adatbázis-kezelő is rendelkezik a felhasznált specifikus funkciókkal
-
úgynevezett escape-szintaxis használata. Az SQL escape-szintaxis azt jelzi
a meghajtóprogramnak, hogy a benne foglalt kódot másképp kell értelmezni. Az
escape-szekvencia mindig kapcsos zárójelpár között áll, és a szintaxisa: {
kulcsszó paraméter } , ahol a kulcsszó az escape-szekvencia fajtáját jelzi
-
az adott adatbáziskezelő-rendszer képességeinek lekérdezése a
DatabaseMetaData interfész felhasználásával
Az SQL utasításokat a következő három
interfész segítségével lehet végrehajtani:
Az egyes fontosabb JDBC osztályokat és
kapcsolatukat a következő ábra szemlélteti:
Az itt ábrázolt osztályok segítségével a
felhasznált adatbázisok szerkezetének ismeretében a leggyakoribb műveletek
könnyen végrehajthatók, de a JDBC definiál az adatbázisok szerkezetének -
például táblái nevének, az oszlopai nevének és típusának -, működési
paramétereinek megállapítására szolgáló osztályokat is.
A Statement interfész tartalmazza az SQL
utasítások végrehajtásához és a visszaadott eredmények feldolgozásához
szükséges alapmetódusokat.
a.) Statement létrehozása
Egy fennálló kapcsolatot reprezentáló Connection objektum createStatement metódusával hozható létre egy Statement objektum.
Az SQL utasítást azonban nem az objektumok létrehozó, hanem az azt végrehajtó
egyik metódusnak kell megadni.
Statement stmt =
con.createStatement();
b.) Statement végrehajtása
A Statement
interfész legfontosabb metódusai:
Egy visszaadott eredménytáblát a getResultSet, adatmanipulációs
utasítások esetén a megváltoztatott sorok számát a getUpdateCount metódussal lehet megkapni.
c.) Statement befejeződése
Az SQL utasítás végrehajtását csak akkor nevezzük befejezettnek,
ha nnak végrehajtása után az összes visszaadott eredménykomponens fel lett
dolgozva. Egy Statement objektum végrehajtásakor ugyanazon objektum esetleges
korábbi végrehajtása által visszakapott eredménytábla automatikusan lezárul. Ez
azt jelenti, hogy egy SQL utasítás újbóli végrehajtása előtt mindig
teljesen fel kell dolgozni az előző végrehajtásból származó esetleges
eredménytáblá(ka)t.
A ResultSet
szintén egy interfész. A ResultSet objektum tartalmazza a lekérdezés
eredményét, a táblázat első sorától kezdődően. Ez azért
kényelmes számunkra, mert egyetlen while ciklussal végig tudunk menni az egész
eredménytáblán. Pl:
Connection con = DriverManager.getConnection(url,
“azonosító”, “jelszó”);
Statement stmt = con.createStatement();
stmt.execute(“SQL-utasítás”);
int rowCount;
while (true) {rowCount=stmt.getUpdateCount()
if
(rowCount>=0) {
System.out.println(rowCount
+ “változott”);
stmt.getMoreResults();
continue;
}
ResultSet
rs=stmt.getResultSet();
if (rs!=null) {
stmt.getMoreResults();
continue;
}
break;
}
Amint láthattuk a ResultSet az eredménytábla
soronként történő elérését, az aktuális sor megfelelő oszlopában
levő értékek kezelését teszi lehetővé. A JDBC 2.0 már lehetővé
teszi az eredménytáblák tetszőleges sorrendben történő feldolgozását,
sőt az eredményeket nemcsak beolvasni, hanem akár módosítani is lehet.
Egy eredménytábla típusát két szempont szerint
csoportosíthatjuk:
- Lehetséges navigálási irány a táblán belül:
- Tábla
tartalom módosíthatóság:
Eredménytáblát a Statement executeQuery és a getResultSet,
valamint a DatabaseMetaData különböző információ-lekérdező metódusai
adnak vissza. Az eredménytáblának mindig csak egy sora, az aktuális érhető
el. Ezt a sort egy külön SQL kurzor jelöli meg. Ez a kurzor kezdetben az
eredménytábla első sora elé mutat, mozgatni pedig a következő
metódusok valamelyikével lehet: next,
previous, last, first, afterLast, beforeLast, absolute, relative. Az utolsó
két metódus kivételével mindenik jelentése magától érthető. Az absolute metódus a kurzort az adott
számú sorra próbálja pozicionálni, a relative
pedig az aktuális pozicióhoz képest relatívan elmozgatni.
Az aktuális sor adott oszlopában álló értéket a gettípusnév alakú metódusokkal lehet
lekérdezni. Egy oszlopra annak sorszámával vagy nevével is hivatkozni lehet.
Egy eredménytábla oszlopairól információt a ResultMetaData interfész
felhasználásával lehet lekérdezni, az oszlopokat leíró objektumot pedig a getMetaData metódussal lehet megkapni.
Egy eredménytábla lezárásával nem kell a
programozónak foglalkoznia – bár megteheti ezt a close metódus segítségével -, az automatikusan megtörténik, ha a
táblát létrehozó Statement lezáródik, újra végrehajtásra kerül, vagy
elkezdődik a következő visszaadott eredménykomponensének a
feldolgozása.
Adatbázis-alkalmazásokban gyakori eset, hogy
ugyanazt az utasítást kell többször vegrehajtani. Egy metódus kezelhet egy információtömböt
és beszúrhatja az egyes elemeket egy adatbázisba, vagy fogadhat sok
különböző nevet vagy más azonosítót és visszaadhatja egy lekérdezés
eredményeit egy vektor minden elemére. Szerencsére a legtöbb RDBMS támogatja a
preparált utasításokat, melyeket egyszer kell létrehozni, elemezni és
optimizálni az adatbázisban, majd újra meg újra használni az alkalmazásban. A
JDBC támogatja a preparált utasításokat a Statement osztály PreparedStatement alosztályával.
Tehát a PreparedStatement interfész a Statement
kiterjesztettje. Abban különbözik tőle, hogy ennek egy példánya már
tartalmaz egy sql utasítást, és hogy ez az sql utasítás tartalmazhat
bemenő paramétereket is. Az utasítás végrehajtása előtt minden
bemenő paraméternek értéket kell adni a megfelelő set metódusok valamelyikével. Mivel ez
az SQL utasítástípus előfordított, ezért gyorsabb a végrehajtás, mint a
Statement objektumok esetén. Tehát az egyik nagy különbség a Statement és a
PreparedStatement között az, hogy a PreparedStatement konstruktora
argumentumként egy SQL utasítást vesz át. Ezáltal a konstruktor az adatbázisban
csak egyszer hozza létre a lekérdezést. A másik különbség az SQL-ben lévő
kérdőjelek. Eltérően a szabályos Statement-től, amely minden
alkalommal újból keletkezik végrehajtás előtt, a PreparedStatement
változatlanul tárolódik a kódon belül. Ha nem lenne mód a PreparedStatement
paramétereinek megváltoztatására, valahányszor végrehajtódik, az egész ötlet
haszontalan lenne. Itt jönnekbe a kérdőjelek. Minden kérdőjel egy
paraméter helyén áll, amely a lekérdezés végrehajtása előtt beállítható.
Az adatbázis ezeket paraméterekkel helyettesíti be, mielőtt végrehajtja a
prekompilált lekérdezést. A
PreparedStatement nemcsak hatékonyabban van implementálva sok adatbázisban, de
sokkal könnyebben használható is a programon belül.
Létrehozása a fennálló kapcsolatot képviselő
Connection objektum prepareStatement
metódusával történik. Az előfordított SQL utasítás létrehozásához maga az
utasítás egyből átadódik az adatbázisnak. Pl: prepareStatement(”UPDATE tábla SET oszl1=? WHERE oszl2=?”)
Végrehajtás előtt minden bemenő
paraméternek be kell állítani az aktuális értékét. A végrehajtó metódusokat
paraméter nélkül kell meghívni, különben SQLException-t fognak kiváltani. Egy
bemenő paraméter értékét a settípusnév
metódusokkal lehet beállítani, a NULL érték pedig a setNULL metódussal állítható be.
A CallableStatement interfész a PreparedStatement
kiterjesztettje. Tárolt SQL eljárások meghívására lehet használni. Egy tárolt
eljárás hívása a bemenő paramétereken kívül kimenő paramétereket is
használhat. Egy paraméter egyszerre lehet kimenő és bemenő paraméter
is.
Létrehozása a Connection objektum prepareCall metódusával történik. Az
eljárás meghívása az escape-szintaxis segítségével történik:
Végrehajtás előtt be kell állítani a
bemenő paraméterek aktuális értékét és minden kimenő paraméternek meg
kell adni a típusát a registerOutParameter
metódus segítségével. Egy kimenő paraméter értékét a gettípusnév alakú metódusokkal lehet lekérdezni. Javasolt, hogy a
maximális hordozhatóság érdekében a kimenő paraméterek értékét csak minden
visszaadott eredménykomponens feldolgozása után kérdezzük le.[2]