A JDBC elmélete - III. rész: SQL utasítások végrehajtása

 

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

 

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.

 

Eredménytáblák kezelése

 

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.

 

A PreparedStatement interfész

 

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 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]

 

Finta Anna Mária - atnif@freemail.hu