JDBC
Témák Mi a JDBC Adatbázisok JDBC használatának lépései Tranzakciók
A JDBC... egy standard Java API relációs adatbázisok használatához Java SE része Felhasználása Kapcsolódás egy adatbázishoz Lekérdezések küldése az adatbázis felé Kapott eredmények feldolgozása
Főbb komponensel A JDBC API JDBC Driver Manager Az adatbázishoz való hozzáférésket kezeli, SQL utasítások küldése az atabázis felé, eredmények feldolgozása, az adatbázis módosítása. java.sql, javax.sql JDBC Driver Manager Kapcsolódás a haszálandó JDBC driver-hez
Relaciós adatbázis áttekintés Az adatbázis (leegyszerűsítve): adatok tárolására alkalmas rendszer, azzal a céllel, hogy az adatok könnyen lekérdezhetőek és feldolgozhatóak legyenek. Relációs adatbázis esetén az adatok táblákba, sorokba, oszlpokba rendezetten jelennek meg. A táblák adatai kapcsolódhatnak egymáshoz. Integritási szabályok: A táblák sora mind egyediek Az adatok nem ismétlődnek, megfelelő táblában tároltak TABLE: STUDENTS | Name | Age | Pet | Pet Name | ---------------------------------------------- | Heather | 10 | Dog | Rex | NULL koncepció: NULL != ‚üres’, NULL != 0..... És NULL != NULL Integritási szabályok biztosítják, hogy a tárolt adatok mindig pontosak és elérhetőek Ha a sorok nem egyedik, a több lehetséges eredmény közül melyik a helyes? Ha minden sor egyedi, akkor megadható egy vagy több oszlop amely egyértelműen azonsítja a sorokat. (elsődleges kulcs) Adatismétlés: számos átalakítási lehetőség -> adatbázsok / normálformák ? Teljesen? Null: olyan helyzetek kezelése, amikor egy adat nem elérhető.
SQL DQL SELECT First_Name, Last_Name FROM Employees WHERE Last_Name LIKE 'Tibi%’ and Car_Number IS NULL DML INSERT INTO table (...) VALUES(...) UPDATE table SET oszlop=.... WHERE .... DELETE FROM table WHERE..... DDL Create, Drop, Alter Table stb.. Insert: ha nem minden mezőt állítjuk be a az oszlopnevek megadása kötelező DDL: adatdefiníció, táblák létrehozás, módosítása, eldobása. Megszorítások, összekapcsolások megadása.
Result set, Cursor A lekérdezés eredményéül kapott sorhalmaz a result set. A result set elemeint soronként érhetjük el egyesével. Ezt a cursor segítségével tehetjük meg, amely egy iterátorként viselkedik. A JDBC api cursora képes a result seten mindkét irányba mozogni
Tranzakciók, Lockok Szükségessé válnak, amikor több felhasználó szeretne ugyanazon adtokkal dolgozni egyidőben. PL.: egy felhasználó sorokat módosít egy táblában, amivel egyidőben egy mások felhasználó ugyanazt a táblát lekérdezi. Lehetséges, hogy a 2. felhasználó részben elavult adatokat kap eredményül. A tranzakciók SQL utasítosok egy csoportja, amely egy logika egységet képez. A trazakciók eredménye vagy commit; vagy rollback; Table Lock: megakadályozza a tábla eldobását, ha nem commitolt trazakció tartozik a táblához. Row Lock: megakadályozza, hogy több tranzakció ugyanazt a sort módosítsa Commit vagy rollbacj szükséges attól függően, hogy fellépett-e valamilyen probléma Commit véglegesíti a tranzakcióhoz tarrotozó utasítások eredményét Rollback visszavonja azokat Lock egy mechanizmus, amely megakadályozza, hogy több tranzakció változtasson ugyanazokon az adatokon Bizonyos adatbázisokban a tableLock egyben a tábla összes sorát is lockolja
JDBC használatának lépései Adatbázis specifikus JDBC driver betöltése Get a Connection object Get a Statement object SQL utasítás végrehajtása Eredmények feldolgozása Close Statement and Connection objects
Adatbázis driver try { Class.forName("com.mysql.jdbc.Driver"); // This loads an instance of the MySQL Driver. // The driver has to be in the classpath. Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException cnfe){ System.out.println("" + cnfe); }
Kapcsolódás az adatbázishoz - DriverManager A megadott adatbázis URL felhasználásval kapcsolódik az adatbázishoz Format jdbc:[subprotocol]:[server-location]/[database-name] Pl.: jdbc:derby://localhost:1527/sample Az adatbázis kapcsolat elkérése: DriverManager.getConnection Connection objektum szálak közötti megosztása nem ajánlott, létrehozásuk és a rajtuk végzett műveletek költségesek. DriverManager.getConnection az adatbázis URL-t kapja paraméterül
Kapcsolódás az adatbázishoz - DataSource Connection Pool és elosztott tranzakciók Connection pool: connection objektumok egy előre létrehozott tárolója, ezek újra felhasználhasnálásra kerülnek a különböző kérésekhez public ConnectionFactory() { dataSource = new ClientConnectionPoolDataSource(); dataSource.setDatabaseName(dbName); dataSource.setUser(user); dataSource.setPassword(pwd); dataSource.setServerName(host); dataSource.setPortNumber(port); } public Connection getConnection() throws SQLException { return dataSource.getPooledConnection().getConnection(); } Connection pool előnye, a sebesség növelése, az adatbázis kapcsolatok felépítésének megspórolásával. Rugalmasabb a driver manager-nél, mivel nem kell megadni a driver nevét a connection url-ben
A connection object java.sql.Connection Statement createStatement() throws SQLException Statementekkel adhatóak meg sql utasítások void close() throws SQLException Connection lezárása void setAutoCommit(boolean b) throws SQLException Tranzakció kezelés. Ha auto commit==true -> minden utasítás külön tranzakció void commit() throws SQLException void rollback() throws SQLException
SQLExceptions Az adatbázissal való munka közben fellépett hibák esetén kapjuk. Kinyerhető Információk: A hiba leírása SQL hibakód Driver implementáció specifikus hibakód amely megegyezhet az adatbázis hibakódjával Warningok SQLWarning az SQLException leszármazottja, a kevésbé kritikus hibákról informál Connection, Statement és a ResultSet objektum esetén getWarnings
Statement létrehozása Lekérdezések végrehajtása PreparedStatement Statement stmt = connection.createStatement(); Általános célú, statikus sql lekérdezések végrehajtására. Nem fogad paramétereket PreparedStatement stmt = connection.prepareStatement(); A Statement-ből származik Dinamikus, többször különböző paraméterekkel futtatandó lekérdezések végrehajtására Megadhatók input paraméterek
Lekérdezések végrehajtása CallableStatement Tárolt eljárások hívására, a PreparedStatement-ből származik. Végrehajtás: boolean execute (String SQL): Ha a visszatérési érték true, elérhető a ResultSet. DDL utasítások végrehajtására int executeUpdate (String SQL): Az érintett sorok számával tér vissza. INSERT, UPDATE, és DELETE utasításokhoz. ResultSet executeQuery (String SQL): Lekérdezések végrehajtásához.
Eredmény feldolgozása Az lekérdezés eredmény egy ResultSet objektumban kaptuk meg. Kezdetben az iterátor az első sor előtt áll, amely a next() metódushívással mozdul az első sorra. while (rs.next()) { // Wrong this will generate an error since column index starts from 1 String value0 = rs.getString(0); // Correct! String value1 = rs.getString(1); int value2 = rs.getInt(2); int value3 = rs.getInt(“ADDR_LN1"); } A ResultSet – nek megfeleő getXXX() metódusa van minden java.sql.Types típushoz. Az oszlopok 1-el kedődően vannak indexelve Hivatkozhatunk rájuk nevekkel (adatbázis column név) vagy indexxel.
ResultSet Az adatok olvasásán kívül azok manipulálásra is tartalmaz műveleteket. ResultSet Típusok TYPE_FORWARD_ONLY: Nem scrollzható result set, a cursor csak előre mozog az első elem előttől az utolsóig. TYPE_SCROLL_INSENSITIVE: A resultset scrollozható, a cursor előre és hátra is mozgatható, abszolút pozícióra ugorhatunk. Bejárás közben az adatokon végzett módosítások nem láthatóak. TYPE_SCROLL_SENSITIVE: Az adaton végzet változások láthatóak (amíg a result set nyitva van) Az alapértelmezett resultSet nem update-elhető és csak előre tud lépni The rows contained in the result set depend on how the underlying database generates the results. That is, it contains the rows that satisfy the query at either the time the query is executed or as the rows are retrieved. Ezek a típusok a createStatement paraméterei
Result set Update Statement stmt = null; try { stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE ); ResultSet uprs = stmt.executeQuery("SELECT * FROM coffees"); while (uprs.next()) { float f = uprs.getFloat("PRICE"); uprs.updateFloat( "PRICE", f * percentage); uprs.updateRow(); } } finally { if (stmt != null) { stmt.close(); }
Statement Batch update A Statement objektumokhoz tartozik egy végrehajtási lista, amely DML utasításokat tartalmazhat. A lista kezdetben üres, az addBatch metódussal tölthető fel és a clearBatch-el üríthető ki. executeBatch metódus egyetlen végrehajtási egységként küldi el az utasításokat az adatbázisnak. A helyes hibakezeléshez, az auto commit-ot ki kell kapcsolni. Paraméterezett Batch update & preparedStatement PreparedStatement pstmt = con.prepareStatement( "INSERT INTO COFFEES VALUES(?, ?)"); pstmt.setString(1, "asd"); pstmt.setInt(2, 49); pstmt.addBatch(); Kizárólag DML utasításokat. (update, insert, delete), amelyek a sorok számával tértnek vissza, és nem resultsettel Paraméterek megadása (?), setXXXX metódusok
Tranzakció példa Feladat: Kölcsönzések kezelése Egy kölcsönzéshez több kölcsönzött dolog tartozhat A dolgok megadott kezdeti példányszámban állnak rendelkezésre Probléma: két kliens ugyanazt a dolgot szeretné kölcsön adni, de csak egy példány van bent. (megszorítás: bent_levo_db >= 0) Táblák: Kölcsönzés(id, dátum, user), Kölcsönzés_elem(kölcsönzés_id, elem_id) Elem(elem_id, bent_levo_db) Kliens 1 Kikölcsönzi ‚A’ dolgot -> sikerül Kikölcsönzi ‚B’ dolgot -> nincs elég Kikölcsönzi ‚C’ dolgot -> ?? Kliens 2. Kikölcsönzi ‚B’ dolgot -> sikerül Elmenti a kölcsönzés adatait Kölcsönzés lépései: Új sor a kölcsönzés táblába Minden elemre: Kölcsönzés_elem felvétele Elem bent_levo_db csökkentése A 2. lépés végrehajtásakor SQLException a megszorítás megsértése miatt A kölcsönzés elem már felvételre került, de valójában nincs elegendő így nem sikerül csökkentenni a bent lévők számát A 3. elem ki is marad a kölcsönzésből Probléma: hibás, hiányos adatokat mentünk az adatbázisba
Megoldás Auto commit off Try { Kikölcsönzi ‚A’ dolgot Kikölcsönzi ‚B’ dolgot Kikölcsönzi ‚C’ dolgot commit; } catch(SQLException e) { rollback; }
Tranzakciós izolációs szintek TRANSACTION_READ_UNCOMMITTED TRANSACTION_READ_COMMITTED Prevents: Dirty Reads TRANSACTION_REPEATABLE_READ Prevents: Dirty Reads, Non-Repeatable Reads TRANSACTION_SERIALIZABLE Prevents: Dirty Reads, Non-Repeatable Reads, Phantom Reads
Tranzakció izolációs problémák Dirty Reads: Nem véglegesített adatok olvasása pl.: nem commitált update Lehetséges, hogy a változtatás visszavonásra kerül az olvasás során Non-Repeatable Akkor történik, amikor egy tranzakció (A) beolvas egy sort, amelyet (B) tranzakció időközben módosít. (A) másodszor is kiolvassa az sort, de különböző értéket lát. Phantom Reads tranzakció (A) beolvas egy sorhalmazt, (B) tranzakció beilleszt egy új sort, (A) másodszor is kiolvassa az sorokat, de különböző számú sort kap ugyanarra a lekérdezésre.
Vége