Adatbázis Rendszerek II. 7. Gy: Oracle – JDBC
B I T MAN
1/104
B Iv: T2015.03.20 MAN
Témakörök
JAVA «-» adatbázis-kezelés
JDBC alapok
Statement
PreparedStatement CallabeStatement
2/104
Tranzakció kezelés
B I T MAN
A cél: Jávás kliensről manipulálni az adatbázist.
3/104
B I T MAN
Kis kitérő Adatbázis elérési módok:
– Beágyazott SQL: egy algoritmikus nyelvbe (C, Pascal, FORTRAN, stb.) ágyazva alkalmazzuk az SQL nyelv elemeit. Az algoritmikus feladatokat a programnyelv, az adatbázissal kapcsolatos műveleteket az SQL végzi. Hátrány: ha változik az adatbázis, teljesen újra kell írni a programot. – ODBC (Open Database Connenctivity): szabványos eljáráskészlet az egyes adatbázisokhoz. Technológia: drivereken keresztül érhetők el az adatbázisok, a driverek felülete egységesen programozható. Így ha változik az adatbázis, csak a drivert kell lecserélni. 4/104
B I T MAN
Kis kitérő (2) Adatbázis elérési módok:
– OO LI (Object Oriented Line Interface): adatbázis elérés objektum orientált módon (JDBC, ADO.NET) – WEB LI: adatbázis elérés webes felületről
5/104
B I T MAN
A probléma és megoldása A Java objektum-orientált, az adatbázisok többnyire még
nem azok. Az adatbázis eléréséhez szükséges egy interfész, ennek kezelése lehet adatbázis függő – API-hívások JNI-n keresztül (Java Native Interface), de lehet adatbázis független is – JDBC (Java Data Base Connectivity). Adatmanipulációs nyelv mindkét esetben az SQL marad.
6/104
B I T MAN
JDBC API Java nyelven íródott osztályokat és interfészeket
tartalmazó csomagok, melyek egy standard API-t biztosítanak adatbázis-keretrendszerek, valamint adatbázis alapú alkalmazások fejlesztésére. A JDBC API előnye abban áll, hogy elvileg bármilyen adatforrást elérhetünk vele bármilyen platformon, melyen a java virtuális gép futtatható. Nem kell tehát minden adatbázisszerverre külön programot írni, hanem ugyanaz a kód működni fog bármely adatbázisszerverrel.
7/104
B I T MAN
JDBC használat Adatbázis feltétel: szükséges egy meghajtó-program
(driver), amellyel az adatbázis-kezelő kielégíti a JDBC specifikációt. A driver rendszerfüggő, az adatbázis gyártójának weblapjáról kell letölteni. Java programozó: a java.sql és a javax.sql
csomagokban található osztályok, metódusok segítségével dolgozik, és a programhoz csatolja a használt adatbázis-kezelő JDBC driver-ét.
8/104
B I T MAN
A megoldás (1.) Kétrétegű megoldás Kliens-oldal
Szerver-oldal
SQL
Driver
9/104
Piros, Kék, Zöld
B I T MAN
A megoldás (2.) Háromrétegű megoldás Kliens-oldal
Szerver-oldal Alkalmazás
DB
SQL
Driver
10/104
Piros, Kék, Zöld
B I T MAN
Témakörök
JAVA «-» adatbázis-kezelés
JDBC alapok
Statement
PreparedStatement CallabeStatement
11/104
Tranzakció kezelés
B I T MAN
Az adatbázis-programozás lépései Kapcsolódás
Lekérdezés
Eredmények feldolgozása
Lekapcsolódás
12/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Driver regisztrálása
Lekérdezés
Kapcsolódás a DBMS-hez
Eredmények feldolgozása
Lekapcsolódás
13/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Eredmények feldolgozása
SQL kérés (STATEMENT) összeállítása
SQL kérés elküldése
Lekapcsolódás
14/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Az eredményhalmaz (CURSOR) rekordonkénti bejárása
Eredmények feldolgozása
Az értékek átadása programváltozóknak
Lekapcsolódás
15/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés Eredményhalmaz lezárása
16/104
Eredmények feldolgozása
SQL kérés lezárása
Lekapcsolódás
Kapcsolat lezárása
B I T MAN
Az adatbázis-programozás lépései B I T M A N Kapcsolódás
Driver regisztrálása Kapcsolódás a DBMS-hez
Lekérdezés
SQL kérés (STATEMENT) összeállítása SQL kérés elküldése
Eredmények feldolgozása
Az eredményhalmaz (CURSOR) rekordonkénti bejárása
Az értékek átadása programváltozóknak Lekapcsolódás
Eredményhalmaz lezárása SQL kérés lezárása
17/104
Kapcsolat lezárása
B I T MAN
JDBC alapok
B I T MAN
Kliens számítógép
18/104
B I T MAN
A JDBC programozás lépései (1) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt (ResultSet) 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 19/104
B I T MAN
DriverManager Feladatai:
– Kezeli a különböző adatbázisok elérését szolgáló driver-eket, – Kezeli a connection-t (kapcsolatot), – Kezeli a statement-eket (SQL kifejezéseket), – Kezeli a resultset-eket (cursorokat).
20/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Driver regisztrálása
Lekérdezés
Kapcsolódás a DBMS-hez
Eredmények feldolgozása
Lekapcsolódás
21/104
B I T MAN
A JDBC programozás lépései (4) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 22/104
B I T MAN
A Driver (meghajtó) betöltése (1) Feltétel: a Java keresési útvonalán elérhető legyen a
fizikai driver. Oracle-höz: ojdbc6.jar Megteremtése: bemásolni a drivert a Java keresési útvonalában szereplő könyvtárba, és telepíteni: set classpath=.; ojdbc6.jar 1.
4.
23/104
2.
3.
5.
B I T MAN
A Driver (meghajtó) betöltése (1) Ha a driver elérhető a keresési útvonalon, regisztrálható Javaban: import java.sql.*; public void Reg(){ try {Class.forName("oracle.jdbc.driver.OracleDriver");} catch (ClassNotFoundException e) { System.out.println("Hibás driver regisztráció!" +e.getMessage());} }
24/104
B I T MAN
A Driver (meghajtó) betöltése (2) Grafikus felületen: import java.sql.*; import java.awt.*; import javax.swing.*;
public void Reg(){ try {Class.forName("oracle.jdbc.driver.OracleDriver");} catch (ClassNotFoundException ex) {JOptionPane.showMessageDialog(null,"Hibás driver regisztráció!", "BitMan mondja: ",2);} }
25/104
B I T MAN
A DriverManager működése A DriverManager osztály tartalmaz egy listát a regisztrált
driverekkel. A getConnection() metódus hívásakor megpróbálja megtalálni a megfelelő drivert, mely kapcsolódni tud az URL-ben megadott adatbázishoz (sorba kipróbálja a drivereket, míg egyet talál, amely kapcsolódik a megfelelő URL segítségével) Ezt a manager-szintet el lehet kerülni direkt Driver metódus hívásával. (csak ritkán használjuk, pl. ha két driver is van, amelyik hozzá tud kapcsolódni egy bizonyos adatbázishoz és explicit szeretnénk meghatározni, hogy melyikkel akarunk kapcsolódni.) 26/104
B I T MAN
A JDBC programozás lépései (4) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 27/104
B I T MAN
Kapcsolat létrehozása public Connection Kapcs(String host, String dbname, String uname, String pword){ Connection conn = null; try { String url = "jdbc:oracle:thin:@"+host+":1521:"+dbname; conn = DriverManager.getConnection(url, uname, pword); } catch (SQLException ex) { System.out.println("AB Kapcsolódás hiba: "+e.getMessage()); conn = null; } return conn; }
28/104
B I T MAN
A kapcsolat lezárása public void Lekapcs(){ try {conn.close();} catch(Exception e) { System.out.println("AB lekapcsolódás Hiba: "+ e.getMessage());} }
29/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Eredmények feldolgozása
SQL kérés (STATEMENT) összeállítása
SQL kérés elküldése
Lekapcsolódás
30/104
B I T MAN
Munka az adatbázisban (1) Amint a kapcsolat létrejött, az adatbázisnak SQL
parancsokat küldhetünk. A JDBC API nem korlátoz a kiadható SQL parancsok tekintetében: azaz adatbázis-specifikus vagy akár nem SQL parancsokat is használhatunk. Azt azonban biztosítanunk kell, hogy az adatbázis fel tudja dolgozni a parancsokat. Pl. hívhatunk tárolt eljárásokat egy olyan adatbázisra, amelyik nem támogatja ezeket, de egy kivétel fog dobódni.
31/104
B I T MAN
Munka az adatbázisban (2) A JDBC API három interfészt biztosít SQL parancsok
küldésére: 1. Statement – paraméter nélküli SQL parancsok hívására 2. PreparedStatement – paraméteres (?), előfordított SQL parancsok hívására 3. CallableStatement – Tárolt eljárások hívására
32/104
B I T MAN
Munka az adatbázisban (3) Végrehajtási módok: 1. executeUpdate():
Adatmanipulációs (INSERT, UPDATE, DELETE) és adatdefiníciós (CREATE/DROP TABLE) utasítások futtatására 2. executeQuery(): Eredménytáblát visszaadó utasítások futtatására (SELECT) 3. execute(): Mindkét típus végrehajtására alkalmas
33/104
B I T MAN
Munka az adatbázisban (4) SQL Statement Select Insert Update Delete Create Drop Alter Tárolt eljárások 34/104
Végrehajtó parancs
Visszatérő érték típusa
executeQuery(sqlp);
ResultSet
executeUpdate(sqlp);
Int
execute(sqlp);
boolean
Magyarázat Rekordok (adatok)
Az érintett sorok száma, vagy 0.
Igaz, ha az első visszatérő adat ResultSet.
B I T MAN
A JDBC programozás lépései (4) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 35/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés Eredményhalmaz lezárása
36/104
Eredmények feldolgozása
SQL kérés lezárása
Lekapcsolódás
Kapcsolat lezárása
B I T MAN
Erőforrások felszabadítása ResultSet lezárása: rs.close(); Statement lezárása: stmt.close(); PreparedStatement lezárása: pstmt.close(); CallableStatement lezárása: cstmt.close(); Kapcsolat lezárása: conn.close();
37/104
B I T MAN
Bolt adatbázis – alapprogram (1)
38/104
B I T MAN
Bolt adatbázis – alapprogram (2)
39/104
B I T MAN
Témakörök
JAVA «-» adatbázis-kezelés
JDBC alapok
Statement
PreparedStatement CallabeStatement
40/104
Tranzakció kezelés
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Eredmények feldolgozása
SQL kérés (STATEMENT) összeállítása
SQL kérés elküldése
Lekapcsolódás
41/104
B I T MAN
Statement A kapcsolat objektum createStatement()
metódusával jön létre, és az executeUpdate() vagy az executeQuery() paranccsal hajtható végre. Statement stmt = conn.createStatement(); Írás jellegű műveletekre: DML (INSERT, UPDATE, DELETE) és DDL (CREATE-, ALTER-, DROP TABLE) int SorDb = stmt.executeUpdate("UPDATE...");
Olvasásra: Select ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1"); 42/104
B I T MAN
A JDBC programozás lépései (2) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 43/104
B I T MAN
Statement használata (1)
44/104
B I T MAN
Kissé életszerűbben
45/104
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Az eredményhalmaz (CURSOR) rekordonkénti bejárása
Eredmények feldolgozása
Az értékek átadása programváltozóknak
Lekapcsolódás
46/104
B I T MAN
A JDBC programozás lépései (3) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 47/104
B I T MAN
ResultSet használata (1)
48/104
B I T MAN
ResultSet használata (2)
49/104
B I T MAN
Módosítható (updateable) ResultSet (1) … Statement s = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); String sqlp = ″select kód, ár from termék where ár > 3000″; ResultSet rs = s.executeQuery(sqlp); … while (rs.next()) { int x = rs.getInt(″ár″); rs.updateInt(″ár″, (int)(x*(0.9))); rs.updateRow(); }
50/104
B I T MAN
Módosítható (updateable) ResultSet (2) ResultSet.TYPE_FORWARD_ONLY – A ResultSet
bejárása csak a legelső rekordtól, egyesével növekedve lehetséges (sor1, sor2, sor3…) – ResultSet.TYPE_SCROLL_INSENSITIVE
– ResultSet.TYPE_SCROLL_SENSITIVE
ResultSet.CONCUR_UPDATABLE – Olvasható és
módosítható a ResultSet. – ResultSet.CONCUR_READ_ONLY
51/104
B I T MAN
Témakörök
JAVA «-» adatbázis-kezelés
JDBC alapok
Statement
PreparedStatement CallabeStatement
52/104
Tranzakció kezelés
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Eredmények feldolgozása
SQL kérés (PreparedStatement) összeállítása
SQL kérés elküldése
Lekapcsolódás
53/104
B I T MAN
PreparedStatement (1) Akkor használjuk, ha egy SQL utasítást többször is
végre akarunk hajtani. Előfordított SQL utasítás – Ha a meghajtó támogatja az előfordítást Hatékonyabb, mint többször egy Statement-et kiadni Paraméterezhető (csak IN típusú paraméterek!) – setXXX metódusok – A paraméter típusának megfelelő setXXX kell! A Statement leszármazottja
54/104
B I T MAN
PreparedStatement (2) A kapcsolat objektum prepareStatement()
metódusával jön létre, és az executeUpdate() vagy az executeQuery() paranccsal hajtható végre. PreparedStatement pstmt = conn.prepareStatement( "UPDATE table1 SET name = ? WHERE id = ?"); pstmt.setString(1, "Joe"); pstmt.setLong(2, 24357); int SorDb = pstmt.executeUpdate(); PreparedStatement pstmt = conn.prepareStatement( " SELECT a, b, c FROM Table1 WHERE id = ?"); pstmt.setInt(1, 4357); B I T MAN 55/104 ResultSet rs = pstmt.executeQuery();
A JDBC programozás lépései (5) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy PreparedStatementet (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A PStatement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a PreparedStatement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 56/104
B I T MAN
PreparedStatement (3) Alkalmazott[ ] beo = ... PreparedStatement ps = conn.prepareStatement( "insert into Alkalmazott" + "(Név, Fizetés, Szülidő) values (?,?,?)" ); for(int i=0; i
"1988.07.16"
57/104
B I T MAN
Bolt – Termékek
58/104
B I T MAN
PreparedStatement (4)
59/104
B I T MAN
Bolt – Termékek (áremelés után)
60/104
B I T MAN
A JDBC programozás lépései (6) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy PreparedStatementet (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A PStatement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a PreparedStatement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 61/104
B I T MAN
PreparedStatement (5) PreparedStatement ps = c.prepareStatement ( "select title, year_made from movies where year_made >= ? and year_made < ?"); for (int ev = 1920; ev < 2000; ev += 10){ System.out.println("=Filmek a "+ev+"-s évekből"); ps.setInt(1, ev); ps.setInt(2, ev+10); ResultSet rs = ps.executeQuery(); while(rs.next()){ cim = rs.getString(1); evs = rs.getInt(2); System.out.println(cim+" - "+evs); } } 62/104
B I T MAN
Témakörök
JAVA «-» adatbázis-kezelés
JDBC alapok
Statement
PreparedStatement CallabeStatement
63/104
Tranzakció kezelés
B I T MAN
Az adatbázis-programozás lépései
Kapcsolódás
Lekérdezés
Eredmények feldolgozása
SQL kérés (CallableStatement) összeállítása
SQL kérés elküldése
Lekapcsolódás
64/104
B I T MAN
CallableStatement (1) Nem-SQL utasítások, pl. tárolt eljárások végrehajtására JDBC eljáráshívási módszer
{ call eljárásnév [<par1>,<par2>, ...] } { ?= call függvénynév [<par1>,<par2> ...] } Lehetnek bemeneti és kimeneti paraméterei
– A kimenetiek típusát regisztrálni kell végrehajtás előtt A visszaadott eredményeket (pl. ResultSet) előbb kell feldolgozni, mint a kimeneti paramétereket A PreparedStatement leszármazottja 65/104
B I T MAN
CallableStatement A kapcsolat objektum prepareCall() metódusával jön
létre, és az execute() paranccsal hajtható végre. CallableStatement cs = con.prepareCall("{call EljNév(?,?)}"); cs.setInt(1, kod); cs.setString(2, feltetel); cs.execute(); CallableStatement cs = con.prepareCall("{? = call FgvNév(?)})";
cs.registerOutParameter(1, java.sql.Types.INTEGER); cs.setString(2, feltetel); cs.execute(); B I T MAN out = cs.getInt(1); 66/104
A JDBC programozás lépései (7) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy CallableStatement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A CStatement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a CallableStatement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 67/104
B I T MAN
Bolt – Tárolt eljárás KatNevMod nevű tárolt eljárás, mely módosítja egy paraméterként megadott kódú kategória nevét. create procedure KatNevMod (kk in char, kn varchar) as begin update Kategoria set Nev= kn where kkod= kk; end;
68/104
B I T MAN
KatNevMod tárolt eljárás létrehozása
69/104
B I T MAN
CallableStatement (2) – KatNevMod hívása
70/104
B I T MAN
CallableStatement (2) – KatNevMod hívása
71/104
B I T MAN
Bolt – Tárolt függvény Bevetel nevű tárolt függvény, mely megadott nap bevételét adja vissza. create or replace function Bevetel (ip varchar) return int as bev int; begin select sum(Ar*Darab) into bev from Termek T inner join Vasarlas V on T.Tkod=V.Tkod where datum = ip; return bev; end;
72/104
B I T MAN
Bevetel tárolt függvény létrehozása
73/104
B I T MAN
CallableStatement (3) – Bevetel hívása
74/104
B I T MAN
CallableStatement (4) CallableStatement cs = conn.prepareCall ( "{ call szabad_helyek( ?, ?, ? ) }" );
IN paraméter OUT paraméter
cs.setString(1, "MA-723"); cs.registerOutParameter(2, java.sql.Types.BOOLEAN); cs.registerOutParameter(3, java.sql.Types.INTEGER); cs.execute(); OUT paraméter // eredmények feldolgozása, ha vannak boolean dohányzó = cs.getBoolean(2); int szabadHelyek = cs.getInt(3); OUT paraméterek
75/104
B I T MAN
CallableStatement (5) CallableStatement cs = conn.prepareCall( "{call updatePrices(?, ?)}"); cs.setString(1, "Colombian"); IN paraméterek, batch végrehajtás cs.setFloat(2, 8.49f); cs.addBatch(); cs.setString(1, "Italian"); cs.setFloat(2, 9.49f); cs.addBatch(); . . . cs.executeBatch();
76/104
B I T MAN
CallableStatement (6) CallableStatement cs = conn.prepareCall( "{call getTestData(?, ?)}"); cs.registerOutParameter(1, java.sql.Types.TINYINT); cs.registerOutParameter(2, java.sql.Types.DECIMAL); ResultSet rs = cs.executeQuery(); // . . . OUT paraméterek byte x = cs.getByte(1); java.math.BigDecimal n = cs.getBigDecimal(2);
77/104
B I T MAN
CallableStatement (7) CallableStatement cs = conn.prepareCall("{call reviseTotal(?)}"); cs.setByte(1, (byte)25); cs.registerOutParameter(1, java.sql.Types.TINYINT); cs.executeUpdate(); byte x = cs.getByte(1); INOUT paraméter!
78/104
B I T MAN
CallableStatement (8) public void performFuncCall() { CallableStatement cs = null; double monthlySalary; Függvény hívás IN paraméter! try { cs = conn.prepareCall("{? = call get_employee_salary(?)}"); cs.registerOutParameter(1,java.sql.Types.INTEGER); cs.setString(2, "A101"); cs.execute(); monthlySalary = cs.getInt(1); cs.close(); System.out.println("Monthly salary is $"+monthlySalary+".\n"); } catch (SQLException e) { e.printStackTrace(); } } B I T MAN 79/104
Témakörök
JAVA «-» adatbázis-kezelés
JDBC alapok
Statement
PreparedStatement CallabeStatement
80/104
Tranzakció kezelés
B I T MAN
Tranzakció kezelés (1) Akkor lehet rá szükség ha több logikailag összefüggő
SQL utasítást szeretnénk együtt (egy blokkban, közvetlenül egymás után) végrehajtani. Ezeknek az SQL utasításoknak általában van egy logikai sorrendje. Ha bármelyik SQL utasítás meghiúsul, akkor a logikailag ráépülő többi eljárást is vissza kell vonni. Példák:
– Több oldalas regisztráció, ahol minden oldalhoz tartozó adat külön SQL utasítással bekerül az adatbázisba. Ha az x. oldal után a felhasználó nyom egy mégse gombot, akkor az eddig végrehajtott SQL insert-eket is érvénytelenítenünk kell. 81/104
B I T MAN
Tranzakció kezelés (2) – Banki műveletek – átutalás egy számláról egy másikra, vagy készpénzfelvétel az automatából: Először megterhelődik az egyik számla a kívánt összeggel, ezután jóváíródik a másik számlán, vagy kiadja az automata. Ha a második lépés meghiúsul (pl.: az automata technikai okok miatt nem tud pénzt kiadni) akkor az első műveletsort is vissza kell vonni. Ezekben az esetekben az SQL utasításokat egy tranzakcióban kezeljük. Ez a teljes tranzakció csak akkor hajtódik végre, ha mi erre a programunkból direkt felszólítjuk, egészen addig az adatbázis-kezelő elkülönítve kezeli őket. A tranzakció közben bármikor lehetőség van arra, hogy az addig kiadott SQL utasításokat érvénytelenítsük, ezzel az adatbázis visszaáll az eredeti állapotához. 82/104
B I T MAN
Tranzakció kezelés (3) A tranzakciók kezelésének módját a Connection object-
en a setAutoCommit() metódussal tudjuk megváltoztatni: connection.setAutoCommit(true): A JDBC alapértelmezésként ezt a beállítást alkalmazza, vagyis nem használ tranzakciókat. Ebben a módban minden egyes kiadott SQL utasítás azonnal végrehajtódik, és nem vonható vissza. connection.setAutoCommit(false): Ebben az esetben (AutoCommit mód kikapcsolva), az SQL utasítások tranzakciókba (csoportokba) rendezhetők, és csak akkor hajtódnak végre vagy vonódnak vissza, ha a connection-ön meghívjuk a commit() vagy rollback() metódusokat. 83/104
B I T MAN
Tranzakció kezelés (4) A commit() hatására a tranzakció utasításai
véglegesen bekerülnek az adatbázisba, míg a rollback() visszaállítja az adatbázist a tranzakció megkezdése előtti állapotába. SavePoint: egy köztes pontot jelöl meg egy tranzakción
belül és lehetővé teszi, hogy egy tranzakció visszagördüljön addig a pontig ahelyett, hogy a teljes tranzakció visszagördüljön. Savepoint sp1 = connection.setSavepoint("sp1"); connection.rollback(sp1);
84/104
B I T MAN
Tranzakció kezelés (5) Egy tranzakcióhoz több Savepoint-ot rendelhetünk.
Ezek automatikusan törlődnek commit vagy teljes
rollback esetében. Ha egy bizonyos Savepoint-ig gördítünk vissza, az utána definiált Savepoint-ok törlődnek. Expliciten is törölhetünk Savepoint-ot: conn.releaseSavepoint(sp1); Ha egy automatikusan vagy expliciten törölt Savepoint-ra hivatkozunk, SQLException kivétel dobódik.
85/104
B I T MAN
A JDBC programozás lépései (8) 1. Regisztráljuk a Driver-t a DriverManager-ben.
2. Létrehozunk egy adatbázis kapcsolatot: a
DriverManager-től kérünk egy Connection-t 3. Tranzakció kezdete 4. A Connection-ben létrehozunk egy Statement-et (beállítjuk a kapcsolatot egy SQL parancs kiadására) 5. A Statement-hez hozzákapcsolunk egy SQL parancsot 6. Ha szükséges, megadjuk az SQL parancs paramétereit 7. Végrehajtjuk a Statement-et 8. Feldolgozzuk az eredményhalmazt 9. Tranzakció vége 10. Felszabadítjuk az erőforrásokat 86/104
B I T MAN
Tranzakciók (2) Connection connection = DriverManager.getConnection(url, username, passwd); connection.setAutoCommit(false); try { statement.executeUpdate(...); statement.executeUpdate(...); connection.commit(); } catch (Exception e) { try { connection.rollback(); } catch (SQLException sqle) { // Hiba esetén } } finally { try { connection.close(); } catch (SQLException sqle) { } } 87/104
B I T MAN
Tranzakció izolációs szintek (1) Azt határozzák meg, hogy hogyan kezelje a szerver az
egyidejű hozzáférési kérelmeket (read, update, insert) ugyanahhoz az objektumhoz (tábla, rekord, …).
1. TRANSACTION_NONE: A tranzakciók nem
támogatottak, nincs tranzakció kezelés. 2. TRANSACTION_READ_UNCOMMITED: Olvasáskor mindig az aktuális (módosított) értéket kapjuk, még akkor is, ha az adott insert/update tranzakciót a kezdeményező nem commit-olta. A következő problémák léphetnek fel: – Dirty reads: A kiolvasott rekord értéke változhat más tranzakciók által a mi tranzakciónk ideje alatt. Tehát előfordulhat, hogy a tranzakciónk elején és végén az adott rekordban más értékek szerepelnek, holott mi nem is változtattuk, csak olvastuk… B I T MAN 88/104
Tranzakció izolációs szintek (2) – Non-repeatable reads: A tábla egy adott sora törlődhet a mi tranzakciónk közben. Így amikor mi a tranzakciónk elején és végén futtatunk egy-egy select-et, akkor a második esetben hiányozhatnak sorok az eredményből. – Phantom reads: Hasonló az előzőhöz, csak inserttel. A táblába új sor (fantom sor) kerülhet egy másik tranzakció által miközben a mi tranzakciónk még fut. Így a tranzakciónk végén több sor lesz az adott táblában, mint amivel számolhattunk az elején…
89/104
B I T MAN
Anomáliák (1) Konfliktusban álló műveletek keveredése:
– Két írás egymás után – lost update w1(x)
w2(x)
– Olvasás két írás között – dirty read w1(x)
r2(x)
w1(x)
– Írás két olvasás között – non repeatable read r1(x)
w2(x)
r1(x)
– Írás két olvasás között – phantom read r1(x) 90/104
w2(x)
r1(x)
B I T MAN
Anomáliák (2) Lost update
1.
BEGIN
A=50
2.
READ(A)
A=50
3.
READ(A)
A=70
4.
A:= A + 20
A=80
5.
A:= A + 30
A=70
6.
WRITE(A)
A=80
7.
WRITE(A)
A≠100
8.
END
Elveszett frissítés w1(x)
91/104
w2(x)
B I T MAN
Anomáliák (3) Dirty read
1.
BEGIN
A=50
2.
READ(A)
A=70
3.
A:= A + 20
A=70
4.
WRITE(A)
A=70
5.
READ(A)
A=50
6. ROLLBACK(A)
A=50
7.
WRITE(A)
A≠70
8.
END
Piszkos olvasás
(ideiglenes frissítés) w1(x)
92/104
r2(x)
w1(x)
B I T MAN
Anomáliák (4) Non repeatable read
Nem megismételhető
1.
BEGIN
A=30
2.
READ(A)
B=20
3.
READ(B)
A=0
4.
DELETE(A)
A=50
5. SELECT(A+B)
A≠20
6.
olvasás r1(x)
93/104
w2(x)
r1(x)
END
B I T MAN
Anomáliák (5) Phantom read
Fantom olvasás r1(x)
w2(x)
r1(x)
S=300 I=20
94/104
1.
BEGIN BEGIN
2.
SUM SUM(WHERE) (WHERE)
3. INSERT(WHERE)
S=320
4.
SUM(WHERE)
S≠S
5.
END
B I T MAN
Tranzakció izolációs szintek (3) 3. TRANSACTION_READ_COMMITED: Olvasáskor mindig
az adott rekord véglegesített értéket kapjuk. Ez az esetek 99%-ra használható, a tranzakcióink mindig csak olyan rekordokat olvasnak, amik véglegesítve vannak, azaz nincs nyitott tranzakció, ami dolgozna rajtuk. A baj ezzel az, hogy ha sokan írják és olvassák az adott rekordot vagy táblát akkor könnyen kialakulhat az a helyzet, hogy az olvasó tranzakciók arra várnak hogy az írás (pl egy nagy tábla update-je) befejeződjön. Ez a főleg a rekordokra vonatkozik így csak a dirty read-től véd, probléma lehet: – a non-repeatable reads, – és a phantom reads. 95/104
B I T MAN
Tranzakció izolációs szintek (4) 4. TRANSACTION_REPEATABLE_READ: Ez annyival jobb
a READ_COMMITTED-nél, hogy már a non-repeatable read hibát is képes kiszűrni a tranzakcióból. Egyszerűbben: csak a rekordok véglegesített értékeit használja, és a rekordok tranzakció közbeni törlése nem befolyásolja a select-eket. Ebben az esetben csak egy probléma marad: – a phantom reads
96/104
B I T MAN
Tranzakció izolációs szintek (5) 5. TRANSACTION_SERIALIZABLE: Annyival több a
REPEATABLE_READ-től, hogy más tranzakció nem írhatja felül a mi tranzakciónk által olvasott értékeket, azaz addig várakoztatja azokat míg be nem fejeződik a tranzakciónk. Így nem fognak tranzakció közben fantom sorok keletkezni a táblában. Itt elég problémás lehet, ha több résztvevő folyamatosan olvas egy táblát, amíg az updatelő szál várakozik, mert a tábla lock-olva van és nem tud bele írni…
97/104
B I T MAN
Tranzakció izolációs szintek (6) Ezek szintek föntről lefelé egyre költségesebbek
lesznek az adatbázisnak, így a tranzakciók végrehajtási sebessége lassul. Az izolációs szinteket a Connection objektumon a setTransactionIsolation() metódussal állíthatjuk
be a tranzakció megkezdése előtt. Például:
connection.setTransactionIsolation( Connection.TRANSACTION_REPEATABLE_READ);
98/104
B I T MAN
Órai feladatok 1.
1. 2. 3.
4.
5.
Készítsen egy JDBC alkalmazást, mely alkalmas a következőkre: Használja a Termek táblát! Készítsen egy Java metódust, mely kilistázza a képernyőre a tábla adatait. A metódus neve legyen TermekLista. Készítsen egy Java metódust, mely beszúr egy beolvasott paraméterekkel megadott rekordot. A metódus neve legyen Beszur. Készítsen egy Java metódust, mely kétlépcsős technikával (prepareStatement) legalább 3 db, valamilyen adatszerkezetben tárolt rekordot szúr be. Az eljárás írja ki a beszúrt rekordok számát. A metódus neve legyen Beszur_2. Készítsen egy Java metódust, mely módosítja egy adott Tkod-ú rekord Ár mezőjében lévő értékét (egy megadott értékre). A metódus neve legyen Modosit. Készítsen menüt a programhoz, mely a TermekLista, a Beszur a Modosit és a Kilépés funkciókat kezeli.
99/104
B I T MAN
Órai feladatok 2.
1.
2. 3.
4.
Készítsen egy JDBC alkalmazást, mely alkalmas a következőkre: Használja a Termek táblát! Készítsen egy Java metódust, melyben létrehoz egy tárolt függvényt. A függvény adja vissza egy megadható kategóriájú termék darabszámát a Termék táblából. Készítsen egy Java metódust, mely lefuttatja az 1. feladatban létrehozott tárolt függvényt, és az eredményt kiírja a képernyőre. Készítsen egy Java metódust, melyben létrehoz egy tárolt eljárást. Az eljárás módosítsa egy megadható kódú termék nevét (egy szintén megadható értékre) a Termék táblában. Készítsen egy Java metódust, mely lefuttatja a 3. feladatban létrehozott tárolt eljárást, ezután visszaolvassa az adatbázisból, és kiírja a képernyőre az adott termék tényleges (módosítás utáni) nevét.
100/104
B I T MAN
Órai feladatok 3. 1.
2. 3.
Készítsen egy egyetlen osztályból álló JAVA programot, mely a main metódusban kapcsolódik az Oracle szerverhez. Készítse el, és futtassa le az alábbi metódusokat: Készítsen egy Java metódust, mely létrehoz egy táblát az Oracle szerveren. A táblában legyen egy KÓD mező, mely legyen numerikus, és legyen elsődleges kulcs. Legyen a táblában egy NÉV mező, és egy NUMERIKUS adatmező, melyben 10000-es nagyságrendű, két tizedes pontosságú adatokat kell tárolni. A tábla sémája [ Kulcs, Név, Num_adat ] Készítsen egy Java metódust, mely beszúr egy statikus paraméterekkel megadott rekordot. Készítsen egy Java metódust, mely kétlépcsős technikával legalább 3, valamilyen adatszerkezetben tárolt kódú rekordot módosít. Az eljárás írja ki a ténylegesen módosított rekordok számát.
101/104
B I T MAN
Órai feladatok 3. 4. 5.
6.
7.
Készítsen egy Java metódust, mely kilistázza a képernyőre a tábla adatait. Készítsen egy Java metódust, melyben létrehoz egy tárolt eljárást. A tárolt eljárás módosítja egy paraméterként kapott azonosítójú rekord numerikus mezőjében lévő értékét egy szintén paraméterként kapott értékre. Készítsen egy Java metódust, mely lefuttatja az 5. feladatban létrehozott tárolt eljárást, ezután visszaolvassa az adatbázisból, és kiírja a képernyőre az adott termék tényleges (módosítás utáni) numerikus értékét. A main metódusban szabadítsa fel a használt erőforrásokat!
102/104
B I T MAN
Felhasznált irodalom Kovács László: Adatbázis rendszerek 2.,
elektronikus jegyzet Barabás Péter: Adatbázis rendszerek 2., elektronikus jegyzet Kozsik Tamás: JDBC, elektronikus jegyzet http://www.cs.ubbcluj.ro/~bittologatok/ - JDBC adatbázis-hozzáférés java-ban, elektronikus jegyzet
103/104
B I T MAN
VÉGE V ÉGE 104/104
B I T MAN