560 likes | 668 Views
Programrendszerek Fejlesztése. 7 / 4. Az előző előadás tartalma:. XPath XSLT XSD. Irodalom. http://www.apl.jhu.edu/~hall/java/Servlet-Tutorial/ http://java.sun.com/j2ee/1.4/docs/tutorial/doc/J2EETutorial.pdf Hans Bergsten: Java Server Pages
E N D
Az előző előadás tartalma: • XPath • XSLT • XSD
Irodalom • http://www.apl.jhu.edu/~hall/java/Servlet-Tutorial/ • http://java.sun.com/j2ee/1.4/docs/tutorial/doc/J2EETutorial.pdf • Hans Bergsten: Java Server Pages • http://web.princeton.edu/sites/isapps/jasig/2004summerWestminster/Presentations/java%20server%20faces.pdf
A mai előadás tartalma • JDBC • Típusai • Kapcsolat típusok • Statement objektumok • RecordSet • Tranzakciók • Hibernate
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)
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
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
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
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
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 http, RMI, … Adatbázis Szever Kliens Középső réteg (Servlet, EJBean) JDBC
JDBC installálása • PostgreSQL • pgjdbc2.jar ->…\lib\ext • postmaster –i • pg_hba.conf • CLASSPATH • windows: • http://www.ejip.net/faq/postgresql_win_setup_faq.jsp
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:<alprotokoll>:<adatbázis hivatkozás> • jdbc:odbc://teszt.com:5000;UID=scott;PWD=tiger • jdbc:postgresql://160.114.36.248/teszt
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)
Példa: import java.sql.*; public class Teszt { public static void main(String args[]) { String url = "jdbc:postgresql://160.114.36.248/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());} } }
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)
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");
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");
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
Metadata – Általános információk • getURL • getUserName • getDatabaseProductVersion, getDriverMajorVersion and • getDriverMinorVersion • getSchemaTerm, getCatalogTerm and getProcedureTerm • nullsAreSortedHigh and nullsAreSortedLow • usesLocalFiles and usesLocalFilePerTable • getSQLKeywords
Metadata-Lehetőségek • supportsAlterTableWithDropColumn • supportsBatchUpdates • supportsTableCorrelationNames • supportsPositionedDelete • supportsFullOuterJoins • supportsStoredProcedures • supportsMixedCaseQuotedIdentifiers • supportsANSI92EntryLevelSQL • supportsCoreSQLGrammar
Metadata - korlátok • getMaxRowSize • getMaxStatementLength • getMaxTablesInSelect • getMaxConnections • getMaxCharLiteralLength • getMaxColumnsInTable
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");
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) { ... } }
Automatikusan Generált Kulcsok • Statement.RETURN_GENERATEDKEYS • getGeneratedKeys(); Statement stmt = conn.createStatement(); int rows = stmt.executeUpdate("INSERT INTO ORDERS " + "(ISBN, CUSTOMERID) " + "VALUES (195123018, ’BILLG’)", Statement.RETURN_GENERATED_KEYS); ResultSet rs = stmt.getGeneratedKeys(); boolean b = rs.next(); if (b == true) { // retrieve the new key value ... }
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
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, "1000010"); ResultSet rs3 = pstmt.executeQuery(); pstmt.setString(1, "Hi"); for (int i = 0; i < 10; i++) { pstmt.setInt(2, i); int rowCount = pstmt.executeUpdate(); } • setNull
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
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();
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);
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);
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
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);
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”);
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, 10101.0f); rs.updateRow();
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();
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); }
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()) { . . . }
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
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
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_UNCOMMITTED); • 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)
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
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
Elosztott tranzakciók • Tranzakció kezelő (JTA) • JDBC meghajtó: • XADataSource • XAConnection • XAResource • Alkalmazás szerver
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; ...
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();
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
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);