Mind itt az önálló labor keretén belül, mind pedig a munkám során többször előkerült már a programkódból való adatbázis elérés, SQL utasítások futtatása. Ebből nyújtanék most egy kis összefoglalót, illetve némiképp összehasonlítást is, mivel az önálló labor során Java-ban, míg munka közben .NET C# alatt dolgozom.
Az alapvető koncepció mindkét esetben, hogy először létre kell hoznunk egy kapcsolatot az adatbázis felé. Később mindig elég erre a kapcsolatra hivatkozunk. A kapcsolat megnyitását követően adhatunk meg SQL parancsokat, akár paraméterezett, akár paraméter nélküli változatban. A parancs futtatásánál mindkét esetben megkülönböztetjük a lekérdező (select) illetve a módosító (update, insert, delete) utasításokat. Lekérdező utasítások esetén a visszatérési érték gyakorlatilag egy tábla, és erre minden esetben szükségünk van a további feldolgozáshoz. Módosító utasításoknál a visszatérési értékre nincs minden esetben szükségünk, így ezt el is lehet hagyni. Ami fontosabb, hogy generálódik-e kivétel, ami az esetleges hibát jelzi.
Szintén mindkét nyelvben fontos, hogy a kivételkezelést ne felejtsük el, mivel az adatbázis műveletek kivételekkel jelzik, ha valamilyen probléma lépett fel a futás során. A kivételt kezelő függvényekben van lehetőség a hiba kezelésére, esetleg még nyitott adatbázis kapcsolatok lezárására.
Lássuk akkor konkrétan, hogy hogyan néz ki mindez a Java nyelvben (az általam használt környezet: JDK 1.6.0, JDeveloper 10g, Oracle 10g R2). Elsőként importolni kell néhány állományt:
import java.sql.*;
import oracle.jdbc.*;
import oracle.jdbc.pool.
Majd definiáljuk a használt változókat:
OracleDataSource ods;
String url;
Connection con;
A kapcsolat létrehozásához létrehozunk egy DataSource –t, majd megadjuk az adatbázist reprezentáló url-t. Java környezetben ezt az alábbi mezők alkotják:
jdbc:oracle:drivertype:user/pwd@host:port/sid
Innen a usernév/jelszó páros elhagyható, ahogy az alábbi példán is látszik, ekkor utólag kell megadni ezeket az adatokat. A driver típusa Java környezetben sokféle lehet, a két legelterjedtebb a thin és az OCI driver. Mivel a JDeveloper automatikusan tartalmaz egy thin drivert, így én ezt használom. Az OCI driver funkcionalitása bővebb, azonban én ezt nem használnám ki igazán.
try
{
ods = new OracleDataSource();
url = "jdbc:oracle:thin:@//localhost:1521/orcl";
ods.setURL(url);
ods.setUser("ONLAB");
ods.setPassword("******");
con = ods.getConnection();
}
catch (Exception ex) {}
Ha már van kapcsolatunk az adatbázissal, akkor futtathatunk SQL utasításokat. Az első eset egy paraméterezett módosító SQL utasítást mutat be. Egy sztringbe írhatjuk bele az utasítást, a paramétereket ’?’-jel jelölve. Ezután létrehozzuk a futtatható paraméterezett utasítást (PreparedStatement), majd megadjuk a paraméterek értékét. Erre egy setXXX utasításcsalád áll rendelkezésre, ahol megadhatjuk a paraméter típusát (XXX a függvény nevében), hogy melyik változót akarjuk megadni (első paraméter, az SQL sztringben balról, 1-gyel kezdve számozódnak a paraméterek) illetve a behelyettesítendő értéket. Nem történik automatikus típuskonverzió, így nekünk kell odafigyelni, hogy a megfelelő setXXX függvényt használjuk. Módosító utasítás futtatásához az executeUpdate parancs használható, melynek visszatérési értéke a módosított / törölt / beszúrt sorok száma.
try
{
String sql =
"insert into users (name, pwd) values (?, ?)";
PreparedStatement insertStmt =
con.prepareStatement(sql);
insertStmt.setString(1, userName);
insertStmt.setString(2, pwd);
insertStmt.executeUpdate();
insertStmt.close();
A második esetben egy nem paraméteres lekérdező utasítást láthatunk. Itt először hozzuk létre a futtatható utasítást (Statement), majd megadjuk az SQL sztringet. A futtatáshoz az executeQuery parancs használható, melynek visszatérési értéke egy ResultSet típusú változó. Ebben a next() függvénnyel léphetünk a következő sorra (visszatérési értéke true, ha létezik még nem olvasott sora az eredménynek), a soron belül pedig a getXXX függvényekkel választhatjuk ki a számunkra szükséges eredményeket, ahol XXX a változó típusát adja meg, a függvény paramétere pedig, hogy hányadik oszlop értéke szükséges (szintén balról, 1-gyel kezdődve számozódik). Paraméterben itt megadható az oszlop neve is, ez azonban némileg lassabb, de kényelmesebb. Ebben az esetben történik automatikus típuskonverzió, azonban ha ez nem lehetséges, akkor SQLException-t kapunk.
Statement selectStmt = con.createStatement();
sql = "select max(user_id) from users";
ResultSet rs = selectStmt.executeQuery(sql);
if (rs.next()) {i = rs.getLong(1); }
selectStmt.close();
con.close();
}
catch (Exception ex) {}
Nézzük ezek után, hogy hogyan működik mindez .NET C# alól (a használt környezet: .NET Framework 2.0, Visual Studio 2005, Oracle 10g R2). Először itt is külső erőforrást veszünk igénybe a using kulcsszó segítségével.
using System.Data.OracleClient;
Majd a specifikus változókat definiáljuk.
OracleConnection conn;
OracleCommand sql;
OracleDataReader reader;
OracleString rowid;
A kapcsolatfelépítéshez itt egy úgynevezett ConnectionString-et kell összeállítani, mely tartalmazza az adatbázis helyi gépen érvényes nevét (DataSource), a felhasználói nevet és a jelszót. Természetesen van más megoldás ennek a sztringnek a létrehozására, megadható például az adatbázis itt is a hosztnév/portszám/sid formátumban is.
try
{
conn = new OracleConnection("Data Source=orcl;" +
"Persist Security Info=True;User ID=ONLAB;" +
"Password=*******");
conn.Open();
A kapcsolat megnyitása után az SQL utasítás összeállítása következik. Elsőként itt is a paraméteres módosító utasítást nézzük. Az utasítást egy sztringgel és a kapcsolat azonosítójával adjuk meg, a sztringben a paramétereket a konvenció szerint :pPARAMÉTER formában adjuk meg. Ezután a paramétereknek értéket adunk az AddWithValue paranccsal, melynek első paramétere a sztringben megadott név, a második pedig a behelyettesítendő érték, minden esetben string típussal. A futtatás az ExecuteOracleNonQuery(out rowid) paranccsal történik, ahol a kimeneti érték az érintett sorok rowID értékét tartalmazza.
sql = new OracleCommand("insert into users " +
"(name, pwd) values (:pNAME, :pPWD)", conn);
sql.Parameters.AddWithValue("pNAME", userName);
sql.Parameters.AddWithValue("pPWD", pwd);
sql.ExecuteOracleNonQuery(out rowid);
Nem paraméteres lekérdező utasítás a második példánk. Az utasítást itt is egy sztringgel és a kapcsolat azonosítójával adjuk meg, majd az ExecuteReader() paranccsal futtatjuk. A visszatérési érték itt egy OracleDataReader típusú változó, melyben a Read() függvénnyel tudunk a következő sorra ugrani (visszatérési értéke true, ha létezik még olvasatlan sor), egy soron belül az oszlopokra pedig a reader[i] kifejezéssel tudunk hivatkozni. Az oszlopok szintén balról, de 0-val kezdődően számozódnak, és van lehetőség oszlopnévvel is hivatkozni az eredményre. Az így kapott érték minden esetben Object típusú, így a konvertálásról nekünk kell gondoskodnunk.
sql = new OracleCommand("select max(user_id)" +
"from users", conn);
reader = sql.ExecuteReader();
if (reader.Read()) i = Int32.Parse(reader[0]);
reader.Close();
conn.Close();
}
catch (Exception ex) {}
Látható tehát, hogy mindkét esetben viszonylag egyszerűen tudunk kapcsolódni egy adatbázishoz és elérni annak tartalmát. Szerintem a .NET-es irány némileg egyszerűbb és átláthatóbb, mennyiségre is kevesebb kóddal oldható meg ugyanaz a probléma. Viszont mindenképpen a Java-s megoldás javára írandó az automatikus típuskonverzió lehetősége és az egyszerűbb paraméterezés.
Utolsó kommentek