9.4.1 JDBC und Transaktionsmanagement Isolation Level und JDBC • Der Isolation Level kann für eine Connection explizit gesetzt werden. Unterstützt ein Treiber den in der Methode setTransactionIsolation(level) übergebenen Level nicht, so darf er eine restriktivere Ebene verwenden. Unterstützt er keine restriktivere Ebene, so wird eine Ausnahme vom Typ SQLException erzeugt. Isolation Level sollten nie innerhalb einer Transaktion, sondern stets nur zwischen zwei Transaktionen geändert werden. void void setTransactionIsolation(int setTransactionIsolation(int level) level) throws throws SQLException; SQLException; Konstanten des Connection-Interfaces TRANSACTION_NONE TRANSACTION_READ_UNCOMMITTED TRANSACTION_READ_COMMITTED TRANSACTION_REPEATABLE_READ TRANSACTION_SERIALIZABLE -- Beispiel: Isolation Level Serializable wird für die gesamte Session gesetzt con.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); Schestag Datenbanken II Kapitel 9 / 30 9.4.1 weitere Connection-Methoden (JDBC) Transaktionsverhalten der Datenbank durch Methoden des Interface Connection: void commit( ) void rollback( ) void setAutoCommit(boolean autoCommit) ) Nach dem Aufbau der Verbindung ist die Datenbank gemäß JDBC-Spezifikation zunächst im Auto-Commit-Modus, d.h. jede einzelne Anweisung wird als eigene Transaktion angesehen, die nach Ende des Kommandos automatisch bestätigt wird (commit). Eine Änderung kann erreicht werden durch Aufruf von setAutoCommit mit Übergabe von false. Danach müssen alle Transaktionen explizit durch Aufruf von commit bestätig bzw. durch rollback zurückgesetzt werden. Nach Abschluss einer Transaktion beginnt automatisch die nächste. Schestag Datenbanken II Kapitel 9 / 31 9.4.1 ResultSetMetaData und DatabaseMetaData (JDBC) Die Methode getMetaData des Interfaces ResultSet liefert ein Objekt vom Typ ResultSetMetaData zur selektierten Datenmenge. Dieses Objekt kapselt Meta-Informationen zur selektierten Datenmenge, z.B. int getColumnCount( ) String getColumnName(int column) String getTableName(int column) int getColumnType(int column) ... Anzahl der Spalten Name einer Spalte Name einer Tabelle Datentyp einer Spalte Die Methode getMetaData des Interfaces Connection liefert ein Objekt vom Typ DatabaseMetaData zur aktiven Verbindung. Dieses Objekt kapselt Meta-Informationen zur aktiven Verbindung, die in die folgenden Kategorien unterteilt werden können: I. Informationen zur Datenbank III. Informationen zu Beschränkungen des Treibers II. Informationen zu unterstützten Features IV. Informationen aus dem Systemkatalog Mit Hilfe der Methode supportTransactionIsolationLevel des DatabaseMetaData-Objektes kann z.B. abgefragt werden, ob eine Datenbank einen bestimmten Isolation Level unterstützt oder nicht. Schestag Datenbanken II Kapitel 9 / 32 9.4.2 JDBC – objektrelationale Konzepte Sämtliche SQL:1999-Datentypen werden von JDBC 2 unterstützt: BLOB, CLOB, ARRAY, STRUCT, REF und DISTINCT Folgende (abstrakte) Interfaces sind im Paket java.sql definiert: Die konkreten JDBC-Treiber müssen also geeignete Klassen bereitstellen, die die jeweiligen Interfaces implementieren, sodass Objekte mit den entsprechenden Interfaces in einem JDBC-Programm erzeugt werden können. JDBC 2 erweitert die Interfaces ResultSet, PreparedStatement und CallableStatement um entsprechende get- und setMethoden. vgl. 9 / 35 Im Hinblick auf die in Kapitel 8 vorgestellten OR-Datentypen ab der Version 8 von Oracle wird im folgenden ausschließlich die Verarbeitung von Array-, Struct- und Ref-Werten beschrieben. Literatur: C. Türker. SQL:1999 & SQL:2003, Objektrelationales SQL, SQLJ & SQL/XML. dpunkt.verlag 2003 Schestag Datenbanken II Kapitel 9 / 33 9.4.2 JDBC – Benutzerdefinierte Typabbildung (1) • Das Mapping zwischen Java und SQL führt eine strukturelle Transformation durch und berücksichtigt nicht die Besonderheiten benutzerdefinierter Typen. Die in SQL definierten Methoden sind nicht in der Java-Umgebung verfügbar: SQL> CREATE TYPE Typ_Kunde AS OBJECT ( KNr INTEGER, Name VARCHAR2(20), Adresse Typ_Adresse, Telefon Typ_Telefon, Kontakt Typ_Kontakt, RefAuftrag Typ_AuftragTab, MEMBER FUNCTION Last_Bestellung RETURN date ); / SQL> ... select a.column_value.anr from t_kunde k, table(k.RefAuftrag) a where k.name = 'Schmidt'; ... Schestag Datenbanken II package oraJdbc; import java.sql.*; ... public class MyJdbc { .... ? ? } Kapitel 9 / 34 9.4.2 JDBC – Benutzerdefinierte Typabbildung (2) • • • • Schestag Die benutzerdefinierte Typabbildung, die JDBC 2 anbietet, ermöglicht eine flexible Abbildung zwischen den Objekten der Datenbank und Objekten in der JavaAnwendung. Die jeweiligen Transformationen werden in entsprechenden Klassen einmal definiert und liegen dann gekapselt zur Wiederverwendung in beliebigen JavaAnwendungen vor. Eine Java-Klasse, die einen SQL-Datentyp repräsentiert, muss das Interface SQLData implementieren: Interface SQLData Der Austausch der Daten zwischen der Java-Anwendung und der Datenbank erfolgt über Ein- und Ausgabedatenströme, die über die Interfaces SQLInput und SQLOutput gelesen bzw. geschrieben werden können. Datenbanken II Kapitel 9 / 35 9.4.2 JDBC – Benutzerdefinierte Typabbildung: Datenfluss (1) • Lesen der Instanz eines SQL-Datentyp von der Datenbank: getObject() SQLData Schestag ... ruft vom Interface SQLData ... readSQL(stream,typeName) ... die Methode readSQL() auf, um einen Strom von Attributwerten in das Java-Objekt einzulesen. SQLInput Das Einlesen erfolgt mit Hilfe des Interfaces SQLInput, ... readXXX() • Initiierung: der JDBC-Treiber erzeugt ein Objekt der zugehörigen Java-Klasse, ... das eine entsprechende read-Methode zur Verfügung stellt. Bei geschachtelten strukturierten Datentypen werden die Attribute in einer Tiefensuchordnung gelesen, d. h. ein Attribut wird vollständig vor dem nächsten Attribut gelesen. Datenbanken II Kapitel 9 / 36 9.4.2 JDBC – Benutzerdefinierte Typabbildung: Datenfluss (2) • Schreiben eines Java-Objektes in die Datenbank: setObject(i, value) SQLData ... ruft vom Interface SQLData ... writeSQL(stream) ... die Methode writeSQL() auf. SQLOutput writeXXX(column) • Schestag Initiierung: der JDBC-Treiber ... Das Schreiben erfolgt mit Hilfe des Interfaces SQLOutput, ... ... das geeignete write-Methoden zur Verfügung stellt. Alle Attribute des Java-Objektes werden in derselben Reihenfolge in den Ausgabedatenstrom geschrieben, wie sie in der Klassendefinition aufgelistet sind. Datenbanken II Kapitel 9 / 37 9.4.2 JDBC – Benutzerdefinierte Typabbildung: Klassendeklaration (1) • Das Beispiel des object-types Typ_Kunde – Klassendeklaration: package oracle10g; public class TypKunde implements SQLData { SQL> CREATE TYPE Typ_Kunde AS OBJECT ( KNr INTEGER, Name VARCHAR2(20), Adresse Typ_Adresse, Telefon Typ_Telefon, Kontakt Typ_Kontakt, RefAuftrag Typ_AuftragTab, MEMBER FUNCTION Last_Bestellung RETURN date ); / ... private private private private private private private String sqlType; int knr; String name; Struct s; Array a1; Array a2; Array a3; public String getSQLTpyeName( throws SQLException { return "SYSTEM.TYP_KUNDE"); ... // weiter s. nächste Folie Schestag Datenbanken II Kapitel 9 / 38 9.4.2 JDBC – Benutzerdefinierte Typabbildung: Klassendeklaration (2) • Fortsetzung: Das Beispiel des object-types Typ_Kunde – Klassendeklaration: ... // Fortsetzung vorhergehende Folie: Klasse TypKunde public void readSQL(SQLInput sqlIn, String typeName) throws SQLException { sqlType = typeName; knr = sqlIn.readInt(); name = sqlIn.readString(); s1 = (Struct) sqlIn.readObject(); a1 = sqlIn.readArray(); a2 = sqlIn.readArray(); a3 = sqlIn.readArray(); } public void writeSQL(SQLOutput sqlOut) throws SQLException { sqlOut.writeInt(knr); sqlOut.writeString(name); sqlOut.writeStruct(s1); sqlOut.writeArray(a1); sqlOut.writeArray(a2); sqlOut.writeArray(a3); } Schestag Datenbanken II Kapitel 9 / 39 9.4.2 JDBC – Benutzerdefinierte Typabbildung: Mapping (1) • ) ) Um eine Beziehung zwischen dem SQL-Datentyp und der JavaKlassendeklaration herzustellen, wird die Klasse java.util.Map genutzt: Mit Hilfe der put-Methode wird dem Namen des SQL-Datentyps (key) der Wert des zugehörigen Java-Typs (value) zugeordnet. Mit Hilfe der get-Methode wird für einen gegebenen SQL-Datentyp der zugehörige Java-Typ zurückgeliefert. key SQL-Typ myMap.put("SYSTEM.TYP_KUNDE“, Class.forName(“oracle10g.TypKunde“) myMap.get("SYSTEM.TYP_KUNDE“) ) Schestag value Java-Typ System.Typ_Kunde TypKunde ... ... Außerdem müssen benutzerdefinierte Typabbildungen für einen Verbindungskontext bekannt gemacht werden: Map Connection.getTypeMap() void Connection.setTypeMap(Map myMap) Datenbanken II Kapitel 9 / 40 9.4.2 JDBC – Benutzerdefinierte Typabbildung: Mapping (2) Das Beispiel des object-types Typ_Kunde – Mapping: ... // Registrierung der benutzerdefinierten Typabbildung java.util.Map myMap = con.getTypeMap(); myMap.put("SYSTEM.TYP_KUNDE", Class.forName("oracle10g.TypKunde"); ... // Ausführung einer SQL-Anfrage Statement stmt = con.createStatement(); String sqlQuery = "SELECT * FROM t_auftrag a WHERE a.anr = 101"; ResultSet rs = stmt.executeQuery(sqlQuery); rs.next(); CREATE TYPE Typ_Auftrag AS OBJECT ( ANr INTEGER, Eingang DATE, Bearb DATE, RefKunde REF Typ_Kunde ); / ... CREATE TABLE T_Auftrag OF Typ_Auftrag ( ANr primary key); // 4. Spalte der Ergebniszeile lesen Ref myRef = rs.getRef(4); TypKunde kunde = (TypKunde) myRef.getObject(myMap); ... // Kundenobjekt ändern und zurückschreiben in die Datenbank kunde.name = "Schmitt"; myRef.setObject(kunde); ...} Schestag Datenbanken II Kapitel 9 / 41