Programrendszerek Fejlesztése 7/47/4 1
Az előző előadás tartalma: 2 XPath XSLT XSD
Irodalom 3 pdf pdf Hans Bergsten: Java Server Pages estminster/Presentations/java%20server%20faces.pdf estminster/Presentations/java%20server%20faces.pdf
A mai előadás tartalma 4 JDBC Típusai Kapcsolat típusok Statement objektumok RecordSet Tranzakciók Hibernate
5 SQL, ODBC SQL (Sturctured Query Language) adatbázis, tábla, sor, oszlop relációs adatbázis lekérdezés módosító lekérdezés nézet ODBC (Open Database Connectivity) X/Open SQL CLI C nyelven alapuló interfész egységes felületet biztosít az adatbázisokhoz a gyártók saját meghajtókat írnak PC szabvány (csaknem ipari szabvány)
6 JDBC A Java platform legfontosabb összetevője Platform és szállító független Egy egyszerű Java API a programozók számára JDBC meghajtó menedzser Gyártó specifikus meghajtók mellyel az egyes gyártók optimalizálhatják a kapcsolatot Hasonló megoldás mint a Microsoft igen sikeres ODBC megoldása (C nyelv) Az adatok titkosítása az szállító meghajtó feladata
7 JDBC JDBC 1.0 SQL 92 egyszerű hívásszintű interfész JDBC 2.0 sokkal összetettebb funkciók, alkalmazásszerverek connection pooling distributed transaction JDBC 3.0 SQL 99
8 JDBC meghajtók JDBC-ODBC bridge plus ODBC driver JDBC-t ODBC-re alakítja az ODBC meghajtó kommunikál az adatbázissal JDBC/ODBC bridge nem támogatja a JDBC2-t az ODBC-t kell beállítanunk nem ajánlott a haszálata Native-API partly-Java driver a meghajtó részben Java nyelven részben más nyelven íródott platform specifikus JDBC-Net pure Java driver egyszerű Java kliens könyvtár mely adatbázis független hálózati protokollon keresztül kommunikál egy szerver komponenssel mely ezt továbbítja az adatbázisnak Native-protocol pure Java driver egyszerű Java könyvtár mely közvetlenül az adatbázissal kommunikál
9 Miért nem ODBC Bonyolult Kevés utasítás, bonyolult szintaxis C specifikus, Pointer függő Kevésbé biztonságos, nehezebben telepíthető mint a JDBC
10 Használata Használható Java alkalmazásokban Applet-ekben csak a szerverrel tud kapcsolatot létesíteni Három, vagy több rétegű alkalmazásokban Kliens Középső réteg (Servlet, EJBean) Adatbázis Szever JDBC http, RMI, …
11 Three-tier Model
12 JDBC installálása PostgreSQL pgjdbc2.jar ->…\lib\ext postmaster –i pg_hba.conf CLASSPATH windows: _faq.jsp
13 JDBC kapcsolat felépítés I. Meghajtó betöltése: try { Class.forName("org.postgresql.Driver"); } catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage()); } java -Djdbc.drivers=org.postgresql.Driver Teszt Adatbázis címzése: jdbc: : jdbc:odbc://teszt.com:5000;UID=scott;PWD=tiger jdbc:postgresql:// /teszt
14 JDBC kapcsolat felépítés II. Kapcsolat objektum: Connection con; con = DriverManager.getConnection(url, "Rendszergazda", ”x"); Kifejezés: Statement stmt; stmt = con.createStatement(); stmt.close(); con.close(); kilépéskor le kell zárnunk minden kapcsolatot !! (a szemétgyűjtő nem tudja megtenni helyettünk a statemenet- et igen)
15 Példa: import java.sql.*; public class Teszt { public static void main(String args[]) { String url = "jdbc:postgresql:// /teszt"; Connection con; String createString; createString = "create table Teszt1 (COF_NAME VARCHAR(32), " + "SUP_ID INTEGER, PRICE FLOAT, SALES INTEGER, " + "TOTAL INTEGER)"; Statement stmt; try {Class.forName("org.postgresql.Driver");} catch(java.lang.ClassNotFoundException e) { System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage());} try { con = DriverManager.getConnection(url, "Rendszergazda", "Alert"); stmt = con.createStatement(); stmt.executeUpdate(createString); stmt.close(); con.close(); } catch(SQLException ex) { System.err.println("SQLException: " + ex.getMessage());} }
16 JDBC kapcsolat felépítés III. Connection Pooling ConnectionPoolDataSource interfész 1:X kapcsolat fizikai kapcsolatok helyett logikai kapcsolatok a kliens nem érzékel semmit Alkalmazás szerver biztosítja ezt a funkciót (Tomcat is)
17 Példa com.acme.jdbc.ConnectionPoolDS cpds = new com.acme.jdbc.ConnectionPoolDS(); cpds.setServerName(“bookserver”); cpds.setDatabaseName(“booklist”); cpds.setPortNumber(9040); cpds.setDescription(“Connection pooling for bookserver”); Context ctx = new InitialContext(); ctx.bind(“jdbc/pool/bookserver_pool”, cpds); com.acme.appserver.PooledDataSource ds = new com.acme.appserver.PooledDataSource(); ds.setDescription(“Datasource with connection pooling”); ds.setDataSourceName(“jdbc/pool/bookserver_pool”); Context ctx = new InitialContext(); ctx.bind(“jdbc/bookserver”, ds); Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup(" jdbc/bookserver"); Connection con = ds.getConnection("user", "pwd");
18 JDBC objektumok
19 Connection Egy kapcsolatot jelent az adatbázissal Egy alkalmazásnak egy-vagy több kapcsolat objektuma lehet, egy- vagy több adatbázissal Connection.getMetaData DatabaseMetaData, információ az adatbázisról DriverManager.getConnection(URL) a DriverManager megpróbál egy megfelelő meghajtót keresni az URL- ben szereplő adatbázishoz DataSource ds.getConnection("user", "pwd");
20 Metadata DatabaseMetaData dbmd = con.getMetaData(); kb. 150 metódust használhatunk a legtöbb resultset objektumot ad vissza sok metódus bonyolult névvel rendelkezik, célszerű olyan metódusokat használni melyek ezeket megadják
21 Metadata – Általános információk getURL getUserName getDatabaseProductVersion, getDriverMajorVersion and getDriverMinorVersion getSchemaTerm, getCatalogTerm and getProcedureTerm nullsAreSortedHigh and nullsAreSortedLow usesLocalFiles and usesLocalFilePerTable getSQLKeywords
22 Metadata-Lehetőségek supportsAlterTableWithDropColumn supportsBatchUpdates supportsTableCorrelationNames supportsPositionedDelete supportsFullOuterJoins supportsStoredProcedures supportsMixedCaseQuotedIdentifiers supportsANSI92EntryLevelSQL supportsCoreSQLGrammar
23 Metadata - korlátok getMaxRowSize getMaxStatementLength getMaxTablesInSelect getMaxConnections getMaxCharLiteralLength getMaxColumnsInTable
24 Statement paraméter nélküli kifejezések egyszerű SQL kifejezések létrehozására használandó executeQuery ( egyszerű lekérdezés Select * from t executeUpdate INSERT UPDATE DELETE CREATE TABLE DROP TABLE a visszatérési értéke egy integer mely az érintett sorok számát adja meg egyébként 0 execute olyan esetekben használják amikor több mint egy válasz érkezik Connection con = DriverManager.getConnection(url, "sunny", ""); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2");
25 Példa: Execute Statement stmt = conn.createStatement(); boolean b = stmt.execute(sql); if (b == true) { // b is true if a ResultSet is returned ResultSet rs; rs = stmt.getResultSet(); while (rs.next()) {... } } else { // b is false if an update count is returned int rows = stmt.getUpdateCount(); if (rows > 0) {... }
26 Automatikusan Generált Kulcsok Statement.RETURN_GENERATEDKEYS getGeneratedKeys(); Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate("INSERT INTO ORDERS " + "(ISBN, CUSTOMERID) " + "VALUES ( , ’BILLG’)", Statement.RETURN_GENERATED_KEYS); ResultSet rs = stmt.getGeneratedKeys(); boolean b = rs.next(); if (b == true) { // retrieve the new key value... }
27 Prepared Statement a Statement alosztálya előre fordított SQL kifejezések egy-vagy több paramétere lehet (IN) több metódust használhatunk az IN paraméterek beállítására sokkal hatékonyabb lehet mint a Statement objektum (előre fordított) gyakran használt kifejezések létrehozására használandó többször futtatható, a beállított paraméterek megmaradnak
28 Példa Connection con = DriverManager.getConnection( "jdbc:my_subprotocol:my_subname"); con.setTransactionIsolation(TRANSACTION_READ_COMMITTED); PreparedStatement pstmt = con.prepareStatement( "SELECT EMP_NO, SALARY FROM EMPLOYEES WHERE EMP_NO = ?", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); pstmt.setFetchSize(25); pstmt.setString(1, " "); ResultSet rs3 = pstmt.executeQuery(); pstmt.setString(1, "Hi"); for (int i = 0; i < 10; i++) { pstmt.setInt(2, i); int rowCount = pstmt.executeUpdate(); } setNull
29 Statement pooling
30 Callable Statement segítségével SQL tárolt eljárásokat futathatunk supportsStoredProcedures() getProcedures() {? = call procedure_name[(?, ?,...)]} IN paraméterek OUT paraméterek regisztrálni kell nincs külön lehetőség nagy adatok kezelésére INOUT paraméterek
31 Példa IN CallableStatement cstmt = con.prepareCall( "{call updatePrices(?, ?)}"); cstmt.setString(1, "Colombian"); cstmt.setFloat(2, 8.49f); cstmt.addBatch(); cstmt.setString(1, "Colombian_Decaf"); cstmt.setFloat(2, 9.49f); cstmt.addBatch(); int [] updateCounts = cstmt.executeBatch();
32 Példa OUT CallableStatement cstmt = con.prepareCall( "{call getTestData(?, ?)}"); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.registerOutParameter(2, java.sql.Types.DECIMAL); ResultSet rs = cstmt.executeQuery(); //... byte x = cstmt.getByte(1); java.math.BigDecimal n = cstmt.getBigDecimal(2);
33 Példa INOUT CallableStatement cstmt = con.prepareCall("{call reviseTotal(?)}"); cstmt.setByte(1, (byte)25); cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.executeUpdate(); byte x = cstmt.getByte(1);
34 Result Set Az előző három objektum eredménye Alapesetben nem írható és nem görgethető (csak egyszer lehet rajta végigmenni) A JDBC 2.0 API ezeket lehetővé teszi Nem minden meghajtó képes erre (pl.: postgresql) getXXX(név vagy sorszám) metódusok (select a, select * ) getMetaData updateRow(), insertRow(), deleteRow(), refreshRow() JDBC 2.0 previous first last absolute relative afterLast beforeFirst
35 Meta Data: ResultSet rs = stmt.executeQuery(sqlString); ResultSetMetaData rsmd = rs.getMetaData(); int colType [] = new int[rsmd.getColumnCount()]; for (int idx = 0, int col = 1; idx < colType.length; idx++, col++) colType[idx] = rsmd.getColumnType(col);
36 Result set (JDBC 3.0) Kurzor: TYPE_FORWARD_ONLY TYPE_SCROLL_INSENSITIVE TYPE_SCROLL_SENSITIVE Párhuzamosság CONCUR_READ_ONLY CONCUR_UPDATABLE Tarthatóság: HOLD_CURSORS_OVER_COMMIT CLOSE_CURSORS_OVER_COMMIT Használata: Connection conn = ds.getConnection(user, passwd); Statement stmt = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT); ResultSet rs = stmt.executeQuery(“select author, title, isbn from booklist”);
37 Result set updateXXX CONCUR_UPDATABLE SQL parancsok nélül módosíthatjuk a rekordokat akkor működnek ha : van elsődleges kulcs a lekérdezés nem tartalmaz JOIN ill. GROUP BY kifejezést int n = rs.getInt(3); // n=5... rs.updateInt(3, 88); int n = rs.getInt(3); // n = 88 rs.absolute(4); rs.updateString(2, "321 Kasten"); rs.updateFloat(3, f); rs.updateRow();
38 Result set insert, delete rs.first(); rs.deleteRow(); rs.moveToInsertRow(); rs.updateObject(1, myArray); rs.updateInt(2, 3857); rs.updateString(3, "Mysteries"); rs.insertRow(); rs.first();
39 Példa java.sql.Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1"); while (rs.next()) { int i = rs.getInt("a"); String s = rs.getString("b"); float f = rs.getFloat("c"); System.out.println("ROW = " + i + " " + s + " " + f); }
40 2. Példa rs.beforeFirst(); while (rs.next()) { System.out.println(rs.getString("EMP_NO") + " " + rs.getFloat("SALARY"); } rs.afterLast(); while (rs.previous()) { System.out.println(rs.getString("EMP_NO") + " " + rs.getFloat("SALARY"); } ResultSet rs = stmt.executeQuery( "SELECT LAST_NAME, FIRST_NAME FROM EMPLOYEES"); rs.last(); int numberOfRows = rs.getRow(); System.out.println("XYZ, Inc. has " + numberOfRows + " employees"); rs.beforeFirst(); while (next()) {... }
41 Tranzakciók bankbetét átutalás A helyen csökken B helyen növekszik egy tranzakció egy vagy több kifejezést tartalmaz melyek csak együtt hajtódnak végre (egyébként visszaállítja az eredeti állapotot - rollback) a kapcsolat objektum auto-commit módban van azaz minden egyes kifejezést külön külön hajt végre ha ez le van tiltva akkor a tranzakció addig nem ér véget amíg a commit vagy rollback metódusokat meg nem hívják a tranzakció kezdete az auto-commit mód letiltásával kezdődik a JDBC 2.0 API segítségével elosztott tranzakciókat is végrehajthatunk JDBC 3.0 SavePoint
42 A tranzakciók elkülönítése piszkos olvasás (dirty read) a tranzakció írásai a commit esemény előtt is olvashatóak azaz valaki olvashatja azt az adatot amit esetleg később visszavonnak (rollback) a többi tranzakció nem konzisztens adatok alapján működhet megismételhetetlen olvasás (nonrepeatable read) A tranzakció olvas egy sort B tranzakció megváltoztatja A tranzakció újra olvassa ugyanazt a megváltozott sort fantom olvasás (phantom read) A tranzakció olvassa az összes sort amely a WHERE feltételben van B tranzakció beilleszt egy sort amely ugyanennek a feltételnek fele meg A tranzakció újraértékeli a kifejezést és beveszi a fantom sort is
43 A tranzakciók elkülönítési szintjei 5 szint: TRANSACTION_NONE nincs tranzakció kezelés TRANSACTION_READ_UNCOMMITTED a nem végleges módosítások láthatóak (dirty read, …) TRANSACTION_READ_COMMITTED csak a végleges adatok olvashatóak (nincs dirty read, de van másik kettő) TRANSACTION_REPEATABLE_READ a másik tranzakció nem is írhatja az A tranzakció által érintett sorokat (phantom még lehet) TRANSACTION_SERIALIZABLE minden problémát kiküszöböl con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTE D); magasabb elkülönítés lassabb működés (sok zárolás, egymásra várnak …) a fentiek természetesen adatbázis-kezelő függőek (MySQL – gyenge tranzakció kezelés)
44 con.setAutoCommit( false ); bError = false; try { for(... ) { if( bError ) { break; } stmt.executeUpdate(... ); } if( bError ) { con.rollback(); } else { con.commit(); } } / catch ( SQLException SQLe) { con.rollback();... } // end catch catch ( Exception e) { con.rollback();... } // end catch
45 Tranzakciók: SavePoint DatabaseMetaData.supportsSavepoints Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) VALUES " + "(’FIRST’)"); // set savepoint Savepoint svpt1 = conn.setSavepoint("SAVEPOINT_1"); rows = stmt.executeUpdate("INSERT INTO TAB1 (COL1) " + "VALUES (’SECOND’)");... conn.rollback(svpt1);... conn.commit(); Connection.releaseSavepoint
46 Elosztott tranzakciók Tranzakció kezelő (JTA) JDBC meghajtó: XADataSource XAConnection XAResource Alkalmazás szerver
47 XADataSource, XAConnection javax.sql XAConnection -> PooledConnection: public interface XAConnection extends PooledConnection { javax.transaction.xa.XAResource getXAResource() throws SQLException; } XADataSource: public interface XADataSource { XAConnection getXAConnection() throws SQLException; XAConnection getXAConnection(String user, String password) throws SQLException;...
48 Példa Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup(“jdbc/inventory”); Connection con = ds.getConnection(“myID”,“mypasswd”); // Assume xads is a driver’s implementation of XADataSource XADataSource xads = (XADataSource)ctx.lookup(“jdbc/xa/" + "inventory_xa”); // xacon implements XAConnection XAConnection xacon = xads.getXAConnection(“myID”, “mypasswd”); // Get a logical connection to pass back up to the application Connection con = xacon.getConnection();
49 XAResource JTA - X/Open Group XA interface XAConnection.getXAResource – egy tranzakció lehet Az alkalmazás szerver ezt adja át a tranzakció menedzsernek Two phase commit Fontosabb metódusok (xid): start end prepare commit rollback
50 Példa javax.transaction.xa.XAResource resourceA = XAConA.getXAResource(); javax.transaction.xa.XAResource resourceB = XAConB.getXAResource(); … resourceA.start(xid, javax.transaction.xa.TMNOFLAGS); resourceA.end(xid, javax.transaction.xa.TMSUCCESS); resourceB.start(xid, javax.transaction.xa.TMNOFLAGS); resourceB.end(xid, javax.transaction.xa.TMSUCCESS); … resourceA.prepare(xid); resourceB.prepare(xid); … resourceA.commit(xid, false); resourceB.commit(xid, false); … resourceA.rollback(xid); resourceB.rollback(xid);
51 Nagy adatmennyiség JDBC 3.0 SQL 3 getXXX, setXXX Array BLOB (Binary Large Object) CLOB (Character Large Object) getCharacterStream JDBC 1.0 LONGVARBINARY LONGVARCHAR getBinaryStream getAsciiStream getUnicodeStream locator
52 Példa java.sql.Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT x FROM Table2"); // Now retrieve the column 1 results in 4 K chunks: byte [] buff = new byte[4096]; while (rs.next()) { Clob cdata = rs. getCLOB(1); java.io.InputStream fin = cdata.getAsciiStream(); for (;;) { int size = fin.read(buff); if (size == -1) { break; } output.write(buff, 0, size); }
53 NULL érték típustól függően kezeli null - karakterekre 0 - számokra false - boolean int n = rs.getInt(3); boolean b = rs.wasNull();
54 Kötegelt utasítások növeli a teljesítményt addBatch() // turn off autocommit con.setAutoCommit(false); Statement stmt = con.createStatement(); stmt.addBatch("INSERT INTO employees VALUES (1000, 'Joe Jones')"); stmt.addBatch("INSERT INTO departments VALUES (260, 'Shoe')"); stmt.addBatch("INSERT INTO emp_dept VALUES (1000, 260)"); // submit a batch of update commands for execution int[] updateCounts = stmt.executeBatch();
55 Függvények használata getNumericFunctions() getStringFunctions() getSystemFunctions() getTimeDateFunctions() supportsConvert() getXXXFunctions() UPDATE myTable SET circularVal = squared * { fn PI() }...
A következő előadás tartalma 56 Hibernate