Ueb12 - oth

Werbung
Datenbanken
12. Übung
JDBC
JDBC: Datenbankzugriff-API
-
Interface für den (entfernten) Datenbankzugriff auf Java-Programme
Applikation kann unabhängig vom darunterliegenden DBMS programmiert werden
setzt die Idee von ODBC auf Java um
gemeinsame Grundlage ist der X/Open SQL CLI (Call Level Interface) Standard
Durch das JDBC-API werden folgende Funktionen zur Verfügung gestellt:
1. Aufbauen einer Verbindung zur Datenbank (DriverManager, Connection)
2. SQL-Anfragen und Update-Anweisungen an die Datenquelle senden
3. Zugriff auf die Ergebnisse einer SQL-Anfrage (ResultSet)
das JDBC-API besteht aus Klassen und Interfaces.
-
Kern: Treiber-Manager
darunter: Treiber für die einzelnen DBS
Angestrebt:
-
DBMS-Client-Server-Netzwerkprotokoll mit pure Java-Treiber
JDBC-Netz mit pure Java-Treiber
Übergangslösungen:
-
-
JDBC-ODBC-Bridge und ODBC-Treiber: Über die JDBC-ODBC-Bridge werden die ODBCTreiber verwendet
Natives API: Der JDBC-Treiber nutzt Bibliotheken, die vom DBMS-Hersteller angeboten
werden. Auch dieser Treibertyp kommt nicht ohne Binärcode aus und kann daher bspw. nicht
in Java-Applets verwendet werden.
JDBC-Net-Treiber: Zwischen JDBC-Treiber und DBMS wird eine zusätzliche
datenbankunabhängige Komponente (Middleware) eingeführt. Der Treiber kommuniziert über
ein DBMS unabhängiges Protokoll mit der Middlewre, er kann also auf der Client-Seite völlig
unabhängig von einem konkreten DBMS gestaltet und vollständig in Java implementiert
werden. Ein Treiber dieser Art eignet sich für den Einsatz in Java-Applets. Zwischen der
Middleware und einem konkreten DBMS wird ein DBMS-spezifisches Protokoll verwendet.
1
Datenbanken
-
Native Protokoll Treiber: Ein Treiber dieser Art kommuniziert direkt mit einer netzwerkfähigen
Datenbank im jeweiligen, DBMS-spezifischen Protokoll. Da indiesem Fall der Client direkt mit
dem Server verbunden ist, erlaubt diese Treibervariante einen effizienten Datenbankzugriff.
JDBC-Treiber-Manager
Driver Manager
-
verwaltet (registriert)Treiber
wählt bei Verbindungswunsch den passenden Treiber aus und stellt Verbindung zur
Datenbank her
Ein JDBC-Treiber ist eine Sammlung von Klassen, die u.a. die Interfaces des JDBC-API
implementieren, zur Ansteuerung einer konkreten Datenquelle. Eine Art Basisklasse für den Treiber
stellt das Interface Driver dar. Jede Driver-Implementierung besitzt einen Konstruktor, der eine Instanz
der Klasse erstellt und diese über die Methode DriverManager.registerDriver() die Liste der
verfügbaren Treiber hinzufügt. Es gibt zwei Methoden, die dafür sorgen, dass der Konstruktor der
Klasse Driver ausgeführt wird:
1. Aufruf der Methode Class.forName(String KlassenName)
2. Hinzufügen der Driver.Klasse zu der Systemeigenschaft (Property) jdbc.drivers
Verbindungsaufbau
- Aufruf an den DriverManager: Connection name = DriverManager.getConnection(jdbcurl,user-id,passwd)
- Datenbank wird eindeutig durch JDBC-URL bezeichnet.
-- jdbc:subprotokoll:subname
-- subprotokoll bezeichnet die Datenbank
-- subname bezeichnet die Treiberart
Bsp.: jdbc:oracle:thin:@rfhs8012.de:1523:ora10g
Connection connection
=
DriverManager.getConnection(url,
"xyz12345") liefert eine offene Verbindungsinstanz connection.
"xyz12345"
,
Verbindungsaufbau beenden: connection.close();
Versenden von SQL-Anweisungen
Statement-Objekte
-
werden durch Aufruf von Methoden einer bestehenden Verbindung connection erzeugt
Statement: einfache SQL-Anweisungen ohne Parameter
PreparedStatement: Vorkompilierte Anfrage, Anfrage mit Parametern
CallableStatement: Aufruf von gespeicherten Prozeduren
Das Statement-Interface
Über die Connection wird eine treiberspezifische Implementierung des Statement-Interfaces
angefordert
Statement name = connection.createStatement();
Über das Statement wird dann eine Anweisung an das DBMS gesendet
- ResultSet statement.executeQuery(string1)
1
string: SQL-Statement ohne Semikolon
2
Datenbanken
Anfragen an die Datenbank. Dabei wird eine Ergebnismenge zurückgegeben.
- int statement.executeUpdate(string)
Einfüge-, Änderungs-, Löschanweisung. Der Rückgabewert stellt die Anzahl der Zeilen dar, die von
der Anweisung bearbeitet wurden
- statement.execute(string)
statement gibt mehr als eine Ergebnismenge zurück (Folge von Tupeln). Ergebnismengen sind
über das Statement-Objekt abfragbar.
Ein Statement-Objekt kann beliebig oft wiederverwendet werden, um SQL-Anweisungen zu
übermitteln.
Mit der Methode close() kann ein Statement-Objekt geschlossen werden.
Behandlung von Ergebnismengen
Klasse ResutSet
ResultSet name = statement.executeQuery(string);
-
-
ResultSet-Objekt unterhält einen Cursor, der mit result-set.next() auf das nächste
Tupel gesetzt wird. Ein Cursor ist ein Iterator über einer Liste von Tupeln, d.h. ein Zeiger der
vor- (und seit JDBC 2.0 auch zurück-) gesetzt werden kann. Das Resultset-Objekt bietet
verschiedene Methoden zur Steuerung der Positionen des Cursors an, mit denen der Cursor
relativ zu seiner vorherigen Position (z.B. next()) oder absolut (z.B. first() oder
absolut(int row) positioniert werden kann.
result-set.next() liefert den Wert false, wenn alle Tupel gelesen wurden.
Zugriff auf die einzelnen Spalten des Tupels unter dem Cursor mit resultset.get<type>(attribute).
<type> ist ein Java-Datentyp zur Spezifikation der get-Methode (getInt(), getFloat(),
getBoolean(), getDate(), getTime(), getString()). Mit get<type> werden die Daten des
Ergebnistupels (SQL-Datentypen) in Java-Typen konvertiert. getString() funktioniert immer
und deckt die SQL-Typen CHAR, VARCHAR ab. "attribute" kann entweder durch
Attributnamen oder durch Spaltennummern angegeben sein. Falls eine get<type> Methode
des Result-Objekts aufgerufen wird, versucht der JDBC-Treiber den jeweiligen SQL-Typ in
den gewünschten Java-Typ zu konvertieren. Diese Konvertierung ist jedoch nicht für alle
Typkombinationen möglich2.
JDBC-Datentypen
-
JDBC steht zwischen Java (Objekttypen) und SQL.
java.sql.types definiert generische SQL-Typen, mit denen JDBC arbeitet
Java-Typ
String
java.math.BigDecimal
boolean
byte
short
int
long
float
double
java.sql.Date
java.sql.Time
JDBC-SQL-Typ
CHAR, VARCHAR
NUMBER, NUMERIC, DECIMAL
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
FLOAT, DOUBLE
DATE(Tag,Monat,Jahr)
TIME(Stunde,Minute,Sekunden)
Abb.: Abbildungsvorschrift zwischen Java- und JDBC-Typen
Informationen über die Spalten von Ergebnismengen
2
Es sollte die Abbildungsvorschrift zwischen Java-Typen und JDBC-Typen eingehalten werden.
3
Datenbanken
ResutSetMetaData name = resultSet.getMetaData() erzeugt ein ResultSetMetaDataObjekt, das Informationen über die Ergebnismenge enthält.
Methode
int getColumnCount()
String getColumnLabel(int)
String getTableName(int)
String getSchemaName(int)
int getColumnType(int)
String getColumnTypeName(int)
-
Beschreibung
Spaltenanzahl der Ergebnismenge
Attributname der Spalte
Tabellenname der Spalte
Schemaname der Spalte
JDBC-Typ der Spalte
Unterliegender DBMS-Typ der Spalte
keine NULL-Werte in Java. resutSet.wasNull() testet, ob der zuletzt gelesene Spaltenwert
NULL war. Die Ausgabe der aktuellen Zeile eines ResultSets kann man damit so vornehmen:
ResultSetMetaData rsetmetadata = rset.getMetaData();
int numCols = rsetmetadata.getColumnCount();
for (int i = 1; i <= numCols; i++)
{ String returnValue = rset.getString(i);
if (rset.wasNull()) System.out.println("null");
else System.out.println(returnValue);
}
-
Mit der Methode close() kann ein ResultSet-Objekt explizit geschlossen werden.
Neben dem Statement-Interface gibt es im JDBC-API zwei Erweiterungen: CallableStatementInterface und PreparedStatement-Interface
Prepared Statements
Dieses Interface fügt zu den bereits im Statement-Interface definierten Methoden die Möglichkeit
hinzu, eine SQL-Anweisung ohne konkrete Parameter an die Datenbank zu senden.
PreparedStatement name = connection.prepareStatement(string);
-
-
SQL-Anweisung string wird vorcompiliert. Damit ist die Anweisung fest im Objektzustand
enthalten. Das ist effizienter als Statement, wenn ein SQL-Statement häufig ausgeführt
werden soll.
Abhängig von string ist nur eine der parameterlosen Methoden
prepared-statement.executeQuery()
prepared-statement.executeUpdate()
prepared-statement.execute()
anwendbar
Parameter
-
Eingabeparameter werden durch "?" repräsentiert, z.B. PreparedStatement pstmt =
conn.prepareStatement("SELECT Population FROM country WHERE Code = ?");
"?"-Parameter werden mit prepared-statement.set<type>(pos,value) gesetzt, bevor
ein PreparedStatement ausgeführt wird.
<type> : Java-Datentyp
pos : Position des zu setzenden Parameters
value : Wert
Bsp.: pstmt.setString(1,"D");
ResultSet rset = pstmt.executeQuery();
…
pstmt.setString(1,"CH");
ResultSet rset = pstmt.executeQuery();
4
Datenbanken
…
-
Nullwerte werden durch setNULL(pos,<type>) gesetzt, wobei <type> den JDBC-Typ
dieser Spalte bezeichnet, z.B. pstmt.setNULL(1,Types.String);
Callable Statements
Ein Callable-Statement erweitert ein Prepared-Statement um die Möglichkeit Datenbankprozeduren
aufzurufen, und die Ergebnisse dieser Prozeduren von der Datenbank anzufordern.
-
-
Erzeugen von Prozeduren und Funktionen mit statement.executeUpdate(string);
(string ist von der Form CREATE PROCEDURE ... )
Bsp.: String s = "CREATE PROCEDURE bla() IS BEGIN ... END";
stmt.executeUpdate(s);
der Aufruf der Prozedur wird als CallableStatement-Objekt erzeugt
die Aufrufsyntax von Prozeduren ist bei den verschiedenen Datenbanksystemen
unterschiedlich
JDBC verwendet eine generische Syntax.
CallableStatement name = connection.prepareCall("{call procedure}");
cstmt = connection.prepareCall("{call bla()}");
Callable Statements mit Parametern:
CallableStatement name = connection.prepareCall("{call procedure(?,…,?)}");
Rückgabewert bei Funktionen:
CallableStatement name = connection.prepareCall("{? = call procedure(?,…,?)}");
Ob die einzelnen "?"-Parameter IN, OUT, oder INOUT-Parameter sind, hängt von der
Prozedurdefinition ab und wird von der JDBC anhand der Metadaten der Datenbank selbstständig
analysiert.
Für OUT-Parameter bzw. den Rückgabewert muß zuerst der JDBC-Datentyp der Parameter mit
cstmt.registerOutParameter(pos,java.sql.Types.<type>) registriert werden. Zum
Lesen des Parameters wird die entsprechende get<type>()-Methode verwendet.
IN-Parameter werden über set<type> gesetzt, z.B. cstmt.setString(2,"Regensburg"); Für
INOUT-Parameter muß ebenfalls registerOutParameter aufgerufen werden. Sie werden
entsprechend mit set<type() gesetzt bzw. mit get<type>() gelesen.
Aufruf mit
ResultSet name = callable-statement.executeQuery()
oder
callable-statement.executeUpdate()
oder
callable-statement.execute()
Sequentielle Ausführung
-
-
-
SQL-Statements,
die
mehrere
Ergebnismengen
zurückliefern:
statement.execute(string),
prepared-statement.execute(),
callablestatement.execute().
Nach der Ausführung mit execute() kann mit getResultSet() bzw. mit
getUpdateCount() die erste Ergebnismenge bzw. der erste Update-Zähler
entgegengenommen
werden.
Um
weitere
Ergebnismengen
zu
holen,
muß
getMoreResults() und dann wieder getResultSet() bzw. getUpdateCount()
aufgerufen werden.
getResultSet() bzw. getUpdateCount(): nächsten Rückgabewert bzw. Update-Zähler
aufrufen. Falls beim Aufruf getResultSet() das nächste Ergebnis eine Ergebnismenge ist,
wird diese zurückgegeben. Ist kein nächstes Ergebnis mehr vorhanden, oder das nächste
Ergebnis keine Ergebnismenge sondern ein Update-Zähler, so wird null zurückgegeben. Falls
das nächste Ergenis ein Update-Zähler ist, wird dieser (eine Zahl n >= 0) zurückgegeben.. Ist
5
Datenbanken
-
das nächste Ergebnis eine Ergebnismenge oder liegt kein weiteres Ergebnis mehr vor, wird –
1 zurückgegeben.
Ist der Aufruf von getMoreResults() true , dann liegt eine Ergebnismenge vor, bei false
ist es ein Update-Zähler bzw. es sind keine weiteren Ergebnis abholbereit.
Alle Ergebnisse sind verarbeitet, wenn ((statement.getResultSet() == null) &&
(statement.getUpdateCount() == -1)) bzw. ((statement.getMoreResults()
== false) && (statement.getUpdateCount() == -1) ist.
SQL-Exception
-
Nahezu jede JDBC-Methode kann eine SQL-Exception als Anwort auf einen
Datenzugriffsfehler auswerfen
Falls mehr als ein Fehler auftritt, werden diese Fehler verkettet
Eine SQL-Exception enthält
-- die Fehlerbeschreibung, die mit getMessage() beschafft werden kann
-- den SQL-Status, der die Annahme festlegt und mit getSQLState() beschafft werden
kann.
-- Einen vom Datenbank-Hersteller spezifizierten Fehler-Code, der mit getErrorCode()
ermittelt werden kann.
-- Eine Verkettungsanweisung, die auf die nächste SQLException mit getNextException()
verweist.
Transaktionen
-
-
-
-
Defaultmäßig wird nach jeder ausgeführten SQL-Anweisung automatisch ein COMMIT an die
Datenbank gegeben
commit kann ausgeschaltet werden mit connection.setAutoCommit(false)
Mit commit können die Veränderungen der Datenbank permanent gesichert werden.
Falls Fehler auftreten, soll mit rollback der Zustand vor Eintreten des Fehlers wiederhergestellt
werden. rollback() löst auch alle Locks, die vom zuständigen Connection-Objekt gehalten
werden.
Zur Vermeidung von Konflikten während einer Transaktion verwendet ein DBMS Sperren
(locks).
 Daten, auf die eine Transaktion zugreift, bleiben für andere Transaktionen gesperrt
 Gesetzte Sperre bleibt solange in Kraft, bis die Transaktion festgeschrieben oder
zurückgerollt wurde.
Isolationsgrad für Transaktionen bestimmt, wie Sperren gesetzt werden. Das Interface
Connection enthält Konstanten, die die Isolationsgrade für Transaktionen repräsentieren, die
man
in
JDBC
verwenden
kann:
TRANSACTION_NONE,
TRANSACTION_READ_COMMITTED, TRANSACTION_SERIALIZABLE
Das Interface Connection stellt eine Methode zur Verfügung, mit der man den Isolationsgrad
abfragen kann: int isoGrad = connection.getTransactionIsolation().
AngJobAbt.java
HalloJdbcAnw.java
InsertBsp.java
LobExample.java
OraJdbc.java
PLSQLExample.java
PLSQLIndexTab.java
ShowBlobImage.java
ShowClobText.java
ueb12a1.sql
ueb12a2.sql
6
Datenbanken
Dokumentation:3
1. Treiber für den JDBC-Zugriff
2. Installation des JDBC-Treibers
3. Grundlagen der JDBC-Anwendung
3.1 Laden des JDBC-Treibers
3.2 Öffnen einer Datenbank
3.3 Senden von SQL-Anweisungen an die Datenbank
3.4 Transaktionsbetrieb
3.5 Hinweise zur Fehlerbehandlung
4. Klassen und Interfaces der JDBC-Schnittstelle
4.1 Die Klasse DriverManager
4.2 Das Interface Connection
4.3 Das Interface CallableStatement
4.4 Das Interface PreparedStatement
4.5 Das Interface Statement
4.6 Das Interface Resultset
5. JDBC-Treiber von Oracle
3
Roland Falkenberg: Schnittstellen zur Programmierung von (Oracle-) Datenbanken, Diplomarbeit an der F.H.
Regensburg
7
Datenbanken
Dokumentation
1. Treiber für den JDBC-Zugriff
Jeder Treiber stellt dem Client eine einheitliche Schnittstelle zur Verfügung. Der Aufbau der einzelnen Treiber
ist intern unterschiedlich und auf ein bestimmtes Zugriffsverfahren, oder aber eines der vorher genannten Zweioder Dreischichtenmodelle zugeschnitten.
Insgesamt gibt es vier verschiedene Typen von JDBC-Treibern.
Java-Anwendung
JDBC-Treibermanager
JDBC-ODBCBridge Treiber
Treiber für DBMS B
(Java)
ODBC-Treiber
Treiber für DBMS B
(C)
Standard - JDBCTreiber
Treiber für DBMS
D (Java)
Middleware
DBMS A
Typ 1
DBMS B
Typ 2
Abb.1: JDBC-Treibertypen
1.
2.
3.
4.
DBMS C
DBMS D
Typ 3
100 % Java
Typ 4
100 % Java
Typ 1 ist eine schnelle Lösung für jede beliebige ODBC-Datenbank. Die JDBC-ODBC-Bridge stützt sich
nach unten hin auf einen bereits vorhandenen ODBC-Treiber und greift dabei einfach auf dessen
Funktionalität zurück.
Dadurch kann man bereits zu einem frühen Zeitpunkt auf jede x-beliebige ODBC-Datenbank zugreifen.
Allerdings hat diese Methode einen gewichtigen Nachteil: der JDBC Treiber besteht nicht aus reinem JavaBytecode, sondern zu einem Großteil auch aus dem ODBC-Treiber, d.h. die Portabilität des Treibers ist
nicht gewährleistet. Clients, die diesen Treiber verwenden sind dadurch an die Plattform gebunden, auf der
der ODBC-Treiber läuft und sind zusätzlich auf die Installation des ODBC-Treibers auf jedem ClientRechner angewiesen.
Ein Typ 1 Treiber ist daher nur eine Übergangslösung für ODBC-Datenbanken, für die noch kein JDBCTreiber existiert.
Ein Typ 2 Treiber ist eine attraktive Lösung für diejenigen Datenbankhersteller, die noch nicht in der Lage
waren, einen eigenen JDBC-Treiber Typ 3 oder Typ 4 zur Verfügung zu stellen. Dieser Treibertyp ist als
aufgesetzte Schicht schnell und einfach zu implementieren, da die Grundfunktionalität bereits in einem
alten, z.B. in C geschriebenen Treiber, vorhanden ist. Auch hier handelt es sich demnach nur um eine
plattformspezifische Übergangslösung.
Typ 3 ist ein vollständig in Java geschriebener Treiber und bietet somit die größtmögliche Flexibilität. Er
fügt sich nahtlos in das Dreischichtenmodell ein. Er kommuniziert über das Netzwerk mit einer Middleware.
Diese bearbeitet sämtliche Anfragen. Ein Beispiel für einen Typ 3 Treiber ist der Treiber der Firma
OpenLink. Dieser Treiber kann jede Datenbank ansprechen, die die Middleware unterstützt.
Der vierte Typ von JDBC-Treibern ist ebenfalls rein in Java implementiert. Er unterstützt allerdings nicht
das Dreischichten- sonder nur das Zweischichtenmodell. Auch der in der Beispielanwendung verwendete
JDBC-Treiber von Oracle ist in diese Kategorie einzuordnen. Diese Treiber werden von den Herstellern für
ihr DBMS selbst entwickelt und ersetzen nach und nach immer mehr die althergebrachten Typ 2 Treiber, die
als Übergangslösungen am Markt existierten. Während ein Typ 4-Treiber aus der Sicht des
Anwendungsentwicklers als ein monolithisches Stück Java-Software erscheint, ist die interne Struktur
komplexer. Schließlich kann der Treiber in seiner Eigenschaft als Java-Klasse nicht unmittelbar Methoden
8
Datenbanken
des Datenbanksystems aufrufen – bislang ist kein relationales DBMS in Java implementiert.4
Auch hier liegt zwischen Treiber und Datenbank eine Middleware, nur mit dem Unterschied, daß es sich um
eine proprietäre Schicht des jeweiligen Herstellers handelt, die nach außen hin unsichtbar und dem
Entwickler nicht zugänglich ist.
Trotz der Vereinheitlichung in der Schnittstelle und der damit verbundenen Portabilität können auch durch
JDBC Treiber nicht alle Probleme behoben werden.
Diese Schwierigkeiten resultieren aus den unzähligen Datenbanksystemen, die auf dem Markt vorhanden sind.
Datenbank ist nicht gleich Datenbank. So unterstützt z.B. jedes DBMS seine eigenen SQL-Features.
Während einfache, grundlegende SQL-Anweisungen, wie etwa ein SELECT in jedem System gleich ist, sieht es
bei proprietären Konstrukten ganz anders aus. Z.B. definiert der SQL-Standard einen SQLSTATE als
Fehlerstatus der Datenbank. Oracle jedoch bietet zusätzlich dazu noch einen SQLCODE, der nicht nur andere
Fehlernummern als SQLSTATE vergibt, sondern zusätzlich dazu statt einem String einen numerischen Wert
zurückliefert. Weiterhin existieren in einigen Datenbanken Konstrukte wie Stored Procedures, bei weitem aber
nicht in allen!
Davon abgesehen wurden mittlerweile verschiedene Standards für SQL definiert, die in ständiger Überarbeitung
auch weiterhin erweitert und verbessert werden.
Der derzeit offiziell gültige Stand ist SQL2, aber das bedeutet nicht, daß alle DBMS diesen Stand voll
unterstützen. Alleine für SQL2 wurden drei verschiedene Level defniert:
Entry Level:
Dieser Level enthält die wenigstens Features. Die Implementierung der Datenbank genügt geringsten
Ansprüchen.
Intermediate Level
Full SQL:
Der volle Sprachumfang wird zur Verfügung gestellt.
„Um in dem Wirrwarr eine halbwegs einheitliche Linie fahren zu können, fordert Sun Microsystems von JDBCTreibern bzw. von den dahinterliegenden Datenbanksystemen, mindestens SQL2 Entry Level zu unterstützen.“ 5
Sun Microsystems bietet den Herstellern von JDBC-Treibern die Möglichkeit, ihr Produkt auf
Standardkonformität zu testen. Bei Erfolg erhält es das Label „JDBC compliant“ und der Benutzer kann sicher
sein, daß sein Treiber SQL2 Entry Level unterstützt.
Natürlich können über einen solchen Treiber die verbleibenden SQL-Eigenschaften einer Datenbank genutzt
werden, die diesem Standard noch nicht entspricht.
Aus all diesen Gesichtspunkten resultieren einige Regeln, die der Anwendungsentwickler berücksichtigen sollte,
wenn sein Produkt möglichst portierbar sein soll:
-
-
-
Bei der Ausprogrammierung sollte möglichst auf die Verwendung von DBMS-Spezifika verzichtet werden!
Sobald eine spezielle Funktion der Datenbank genutzt wird, ist die Anwendung an dieses System gebunden.
SQL2 Entry Level sollte eingehalten werden. Ist die darunterliegende Datenbank mit diesem Stand noch
nicht ausgerüstet, so muß die Entwicklung auf die verbliebenen Eigenschaften des Datenbanksystems
beschränkt werden.
Immer auf das Label „JDBC compliant“ achten!
JDBC und ODBC sind eng verwandt. Auch in JDBC existieren SQL-Escapes mit deren Hilfe DBMSunabhängige Anwendungen geschrieben werden können. Solche Escapes erleichtern z.B. das Einfügen eines
Wertes in ein Datumsfeld, das von jedem DBMS in einem anderen Format verwaltet wird.
Eine große Hilfe bei der „Erforschung“ der Möglichkeiten einer Datenbank sind die Metadaten. Über den
JDBC-Treiber können vom DBMS Informationen über den Namen des Produkts, den Hersteller und sogar
über Features des Systems abgefragt werden.
Ein Aufruf von supportsStoredProcedures() beispielsweise gibt Aufschluß darüber, ob das Datenbanksystem
Stored Procedures verwalten kann. Ob das System SQL2 Entry Level erfüllt, erfährt man über
supportsANSI92EntryLevelSQL().
Die Oracle Corporation stellt für ihr DBMS einen JDBC-Treiber Typ 4 zur Verfügung.
Dieser Treiber wurde für die Entwicklung des Java-Clients, der in einem späteren Kapitel vorgestellt wird,
sowohl unter UNIX als auch unter Windows95 und Windows NT installiert.
4
5
Rainer Klute: JDBC in der Praxis, Addison-Wesley, S. 41
Rainer Klute: JDBC in der Praxis, Addison-Wesley, S. 45
9
Datenbanken
2. Installation des JDBC-Treibers
Der JDBC-Treiber kann bei Oracle bezogen werden6.
Die thin Versionen werden für einen Datenbankzugriff über das Internet benötigt. Die normale Version
ermöglicht den Zugriff über ein lokales Netz. Die Versionsangaben bei den Files beziehen sich auf die Oracle
Serverversion, für die der Treiber gedacht ist.
Das Softwarepaket enthält eine ausführliche Installationsanleitung für die Betriebssysteme UNIX und Windows.
Es sei darauf hingewiesen, daß die Pfadangaben, die in diesen Installationshilfen gemacht werden, unbedingt
einzuhalten sind, d.h. daß die Files, die laut Beschreibung im [ORACLE HOME] Verzeichnis stehen sollen,
auch unbedingt dort hinkopiert werden müssen! Weiterhin ist unter beiden Betriebssystemen die
Umgebungsvariable CLASSPATH um den Pfadeintrag auf die classes111.zip ( ab JDK 1.1 ) zu ergänzen,
also z.B. /soft/oracle7.3/jdbc/lib/classes111.zip unter UNIX.
Um in einem Applet auf eine Datenbank zugreifen zu können muß sich eine Kopie der classes111.zip
unbedingt im selben Verzeichnis befinden wie die Klasse, die den Zugriff auf die Datenbank initiiert!
In der HTML-Datei, die ein Applet startet, muß unter den Tags für den Applet-Aufruf ein
archive=“classes111.zip“ eingefügt werden.
Für die Beispielanwendung wurde ein JDK-1.1.x kompatibler Treiber gewählt. Unter Unix beinhaltet das
Softwarepaket eine Datei liboci73jdbc.so, deren Pfad entweder in der Umgebunsgvariablen
LD_LIBRARY_PATH eingetragen werden muß, oder aber in ein Verzeichnis kopiert werden sollte, das in
dieser Systemvariable bereits eingetragen ist.
In gleicher Weise wird mit den Dateien oci73jdbc.dll und oci73jdbc_g.dll unter Windows verfahren. Der Eintrag
erfolgt in die %PATH%-Umgebungsvariable.
Ein geeigneter Ort, die Kopien dieser Dateien abzulegen, ist %ORACLE_HOME%/Bin, da dieser Pfad
standardmäßig vom Oracle Installer in den Umgebungsvariablen eingetragen wird.
3. Grundlagen der JDBC-Anwendung
3.1 Laden eines JDBC-Treibers
Das Laden der JDBC-Klassen erfolgt über zwei Import-Anweisungen:
import java.sql.*;
import java.math.*;
Der erste Import stellt die reinen JDBC-Klassen zur Verfügung, der zweite fügt die BigDecimal Klassen hinzu.
Weiterhin muß der Treiber selbst geladen werden. Dies geschieht über die Anweisung:
Class.forName( "oracle.jdbc.driver.OracleDriver" );
Der Treiber selbst ist eine gewöhnliche Java-Klasse. Das ungewöhnliche an dieser Vorgehensweise ist, daß diese
erst zur Laufzeit des Programms hinzugebunden wird.
Hierfür bedient sich die Java Virtual Machine des Classloaders. Die Klasse, die geladen werden soll, muß sich in
einem Pfad, einer ZIP- oder JAR- Datei befinden, die im CLASSPATH eingetragen ist (siehe
Installationshinweise).
Ist der Classloader nicht in der Lage, dieTreiberklasse hinzuzubinden, erzeugt er eine
java.lang.ClassNotFoundException.
Wird der Treiber erfolgreich geladen, meldet er sich mit seinem Initialisierungscode beim JDBC-Treibermanager
an.
Selbstverständlich kann ein Programm viele verschiedene JDBC-Treiber gleichzeitig laden, um verschiedene
Datenbanken parallel anzusprechen. Dabei sind die einzelnen Treiber meistens herstellerspezifisch.
Im Falle des Oracle-Treibers wird empfohlen, den JDBC-OCI Treiber zu registrieren. Dies erfolgt mit Hilfe des
Aufrufs von
6
Bei direktem Ansteuern der Treibersoftware über den Browser ist die Einsendung einer Registrierung
erforderlich: http://www.oracle.com
Oracle stellt allerdings auch einen direkten Download über den hauseigenen FTP-Server zur Verfügung:
ftp://ftp.oracle.com/pub/www/jdbc
10
Datenbanken
DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver());
3.2 Öffnen einer Datenbank
Das Öffnen der Datenbank kann unter Verwendung zweier Methoden erfolgen. Die erste Methode, die nur für
den direkten Aufruf des OCI –Connects geeignet ist, verwendet den Datenbankalias oder TNSName, der in der
tnsnames.ora spezifiert wird.
Connection conn =
DriverManager.getConnection ("jdbc:oracle:oci7:@mydatabase","scott",
"tiger");
Scott ist in diesem Fall der Username, Tiger das Passwort und @mydatabase der TNSName der Datenbank.
Weiterhin ist angegeben, daß es sich um einen Aufruf des OCI7 Treibers handelt.
Eine weitere Möglichkeit, das Öffnen der Datenbank durchzuführen, falls keine sauber erstellte Datei
tnsnames.ora vorliegt, ist die Ergänzung des Strings um eine gültige SQL*Net Namensspezifikation:
Connection conn =
DriverManager.getConnection
("jdbc:oracle:oci7:@(description=(address=(host=myhost)
(protocol=tcp)(port=1521))(connect_data=(sid=orcl)))","scott",
"tiger");
Man erkennt die Ähnlichkeit zu den Eintragungen in der Datei tnsnames.ora. Im Connectstring werden
direkt der Hostname, das Protokoll und der Port angegeben. Weiterhin enthält er eine SID (System Identifier),
hier den String ‚orcl‘. Username und Passwort bleiben gleich.
Diese Aufrufe gelten aber nur für eine Verbindung über das Oracle Call Interface von einem normalen JavaProgramm aus.
Im Falle eines Applets wird der Zugriff auf die Datenbank über das Internet gewünscht. Selbstverständlich ist für
diese Art der Verbindung das SQL*Net nutzlos, da nicht jeder Client-Rechner über eine Oracle-Installation
verfügen muß, um online auf eine Datenbank zuzugreifen. Für diese spezielle Zugriffsmöglichkeit wurde der
Oracle JDBC Thin Treiber konzipiert.
Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:scott/[email protected]:1527:oradb"
);
Im Connectstring wird das ‚OCI7‘ durch ‚thin‘ ersetzt. Name und Passwort bleiben gleich, die Änderung in der
Zusammensetzung des Strings ist optional.
Nach dem @ wird der komplette Hostname eingetragen. Der Port 1527 ist derjenige, auf dem die Datenbank mit
dem Identifizierer oradb über ihre Listener auf Anfragen wartet. Das verwendete Protokoll ist selbstverständlich
TCP/IP.
Auch für diesen String gibt es eine zweite Möglichkeit:
Connection conn =
DriverManager.getConnection
("jdbc:oracle:thin:@(description=(address=(host=myhost)(protocol=tcp)
(port=1521))(connect_data=(sid=orcl)))", "scott", "tiger");
Der Connectstring im Falle eines JDBC-Aufrufs nennt sich JDBC-URL. Die Methode getConnection()
gehört zur Klasse DriverManager. „Der Treibermanager überprüft, welcher der geladenen Treiber den
angegebenen JDBC-URL öffnen kann, und ruft die entsprechende Methode dieses Treibers auf.“7
Als Ergebnis liefert die Methode ein Objet vom Typ Connection. Dieses Connection Objekt ist für alle weiteren
Datenbankoperationen notwendig.
7
Rainer Klute: JDBC in der Praxis, Addison-Wesley, S. 74
11
Datenbanken
3.3 Senden von SQL-Anweisungen an die Datenbank
Der Client sendet seine SQL-Anweisungen über ein Objekt vom Typ Statement oder PreparedStatement an die
Datenbank. Um dieses Objekt zu generieren, wird eine Methode der Klasse Connection aufgerufen. Im
nachfolgenden Beispiel sei die Variable con eine Instanz der Klasse Connection:
Statement stmt = con.createStatement();
Die eigentliche SQL-Anweisung, INSERT, DELETE oder UPDATE, werden in einer Stringvariablen definiert,
z.B.
String SQL = “DELETE FROM Benutzer“;
Achtung: im Falle des JDBC-Treibers von Oracle werden abschließende Strichpunkte innerhalb der SQLAnweisung als Fehler gewertet. Dabei handelt es sich mit großer Wahrscheinlichkeit um einen Fehler des
Treibers, da der schließende Strichpunkt dem Standard von SQL (und auch des RDBMS von Oracle) entspricht!
Der oben definierte String wird über das stmt-Objekt vom Typ Statement an die Datenbank geschickt:
ResultSet rset = stmt.executeUpdate( SQL );
Die Methode executeUpdate() liefert 0 oder die Anzahl der betroffenen Datensätze zurück. Sie wird für
INSERT, DELETE und UPDATE verwendet, sowie für DDL-Befehle, die keine Ergebnismenge erzeugen.
Eine SELECT-Anweisung wird über die Methode:
ResultSet rset = stmt.executeQuery( SQL );
auf der Datenbank abgesetzt. Dabei wird eine Ergebnismenge im ResultSet zur Verfügung gestellt.
3.3 Transaktionsbetrieb
Normalerweise wird jedes SQL-Statement, das via JDBC an die Datenbank übermittelt wird, sofort und
dauerhaft auf dem Datenbestand durchgeführt, das heißt, es wird ein automatischer COMMIT abgesetzt.
In manchen Situationen ist es für den Erhalt der Datenkonsistenz zwingend erforderlich, daß mehrere Aktionen
erfolgreich abgeschlossen sein müssen, bevor die Änderungen wirksam werden können, d.h. entweder alle SQLAnweisungen müssen erfolgreich ausgeführt werden, oder aber keine!
Die Anwendung muß, um in den Transaktionsbetrieb zu schalten, die AutoCommit Funktion abschalten, die
beim Verbindungsaufbau standardmäßig aktiviert wird. Da es sich um eine Eigenschaft der Verbindung zur
Datenbank handelt, wird hierfür eine Methode der Klasse Connection verwendet:
Connection.setAutoCommit(false);
Um nun zu einem definierten Zeitpunkt die Änderungen wirksam werden zu lassen oder sie gänzlich zu
verwerfen, kann auf der Datenbank mit Connection.commit() jegliche Änderung bestätigt werden, oder
mit Connection.rollback() der Urzustand des Datenbestandes wieder hergestellt werden.
Ob nun AutoCommit ein- oder ausgeschaltet ist, läßt sich über Connection.getAutoCommit()
feststellen.
„Die sogenannte Transaktions-Isolation regelt, wie Transaktionen voneinander abgeschottet sind. JDBC
definiert fünf Abstufungen, die sich per Connection.setTransactionIsolation() einstellen lassen.
Die aktuelle Einstellung verrät ein Aufruf von Connection.getTransactionIsolation().“8
Die einzelnen Stufen der Isolation sind als Konstanten in der Connection Klasse definiert.
8
Rainer Klute: JDBC in der Praxis, Addison-Wesley, S. 134
12
Datenbanken
TRANSACTION_NONE
TRANSACTION_READ_UNCOMMITTED
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE
Keine Unterstützung von Transaktionen
Transaktion B kann Daten lesen, die Transaktion A
geändert, aber noch nicht per commit() dauerhaft an die
Datenbank übergeben hat („Dirty Read“).
„Dirty Reads“ sind nicht möglich. Die Transaktion B kann
nur solche Daten lesen, die Transaktion A bereits per
commit() dauerhaft an die Datenbank übergeben hat. Da
während der Ausführung von B jedoch parallele Transaktionen die gleichen Daten mehrfach ändern können, erhält
B beim wiederholten Lesen eines Tupels nicht unbedingt
immer die gleichen Daten („Non-repeatable read“).
„Dirty Reads“ und „Non-repeatable reads“ erfolgen nicht.
Es kann aber passieren, daß Transaktion A ein neues Tupel
in eine Tabelle einträgt, das Transaktion B beim
wiederholten Lesen erhält („Phantom read“).
„Dirty reads“, „Non-repeatable reads“ und “Phantom reads“
erfolgen nicht. Transaktionen, die auf die gleichen Daten
zugreifen, werden serialisiert, also nacheinander ausgeführt.
Abb. 2: Stufen der Transaktions-Isolation in JDBC9
Die Datenbank arbeitet am schnellsten, wenn sich die Transaktionen nicht gegenseitig behindern, d.h. im Modus
TRANSACTIONS_NONE. Maximale Datenintegrität wird nur durch den letzten Modus,
TRANSACTION_SERIALIZABLE, gewährleistet. Der JDBC-Treiber initialisiert keinen dieser Modi, sondern
verwendet die Voreinstellung der Datenbank.
Eine Änderung des Modus löst einen COMMIT auf der Datenbank aus. Während einer laufenden Transaktion
darf der Modus demnach nicht geändert werden.
Informationen über die Art und Weise, wie die Datenbank Transaktionen unterstützt, können über die Methoden
der Klasse DatabaseMetaData erhalten werden.





9
supportsTransactions()
Database Management Systems nach SQL2 Standard unterstützen auf jeden Fall Transaktionen.
supportsMultipleTransactions()
gibt an, ob ein DBMS auch über verschiedene Verbindungen mehrere Transaktionen gleichzeitig unterstützt.
getDefaultTransactionIsolation()
Welche Isolationsstufe ist standardmäßig für die Datenbank eingestellt?
supportsTransactionIsolationLevel(n)
liefert die Information, ob ein DBMS eine bestimmte Isolationsstufe n unterstützt.
dataDefinitionIgnoredInTransactions(),
dataDefinitionCausesTransactionCommit(),
supportsDataDefinitionAndDataManipulationTransactions(),
supportsDataManipulationTransactionsOnly()
liefern Informationen darüber, welche Operationen bei Datendefinitionsanweisungen innerhalb einer
Transaktion durchgeführt werden.
Rainer Klute: JDBC in der Praxis, Addison-Wesley, S.134
13
Datenbanken
3.5 Hinweise zur Fehlerbehandlung
Jede Funktion, die eine Operation in Verbindung mit der Datenbank durchführen soll, muß entweder eine
throws SQLException
Anweisung beinhalten, oder den Anweisungsteil in einem try{}-Block durchführen.
Generell existiert für jeden möglichen SQL-Fehler ( Exception ) eine eigene Fehlernummer und -meldung. Die
standardisierte Fehlernumerierung erfolgt üblicherweise durch eine Variable SQLSTATE. Im Fall des JDBCTreibers von Oracle scheint das RDBMS diesen Standard jedoch nicht zu unterstützen (die entsprechende
Funktion für das Auslesen des SQLSTATES existiert zwar im SQL-Package von Java, wird aber nicht
verwendet).
Oracle bietet produktspezifisch eine Ausgabe des sogenannten SQLCODE. Leider wird dadurch die Portabilität
eines JDBC-Clients, der unter Oracle entwickelt wurde, vermindert.
Die entsprechende Funktion zur Abfrage des SQLCODE ist eine Methode von SQLException und lautet
getErrorCode().
Während SQLSTATE gewöhnlich durch eine CHAR Repräsentation der Fehlernummer dargestellt wird, liefert
der SQLCODE einen Integer Wert.
4. Klassen und Interfaces der JDBC-Schnittstelle
4.1 Die Klasse DriverManager
Der DriverManager ist in der Lage, eine größere Anzahl von JDBC-Treibern zu verwalten. Sollte in der
Systemumgebung ein JDBC-Treiber als Standard definiert sein, so versucht der DriverManager, diesen zu laden.
Zudem können dynamisch jederzeit weitere Treiber nachgeladen werden. Dies geschieht über den Aufruf des
ClassLoaders über Class.forName().
Anhand der JDBC-URL versucht der DriverManager bei Aufruf der Methode getConnection() den
richtigen Treiber ausfindig zu machen und die Datenbankverbindung zu initialisieren.
Die wichtigsten Methoden:




deregisterDriver(Driver)
Ein Treiber wird aus der Liste der registrierten Treiber gelöscht.
getConnection(…)
Die Methode erwartet entweder einen einzelnen String, drei Strings oder einen String und ein Objekt vom
Typ Properties als Übergabeparameter.
Der einzelne String ist ein JDBC-URL des Typs
„jdbc:oracle:thin:scott/[email protected]:1527:oradb",
bei drei Stringparametern wird dieser Block aufgesplittet in URL, Name und Passwort. Die dritte Form
erwartet den JDBC-URL und eine Parameterliste in Form von Tags oder Strings, die zumindest die
Username und Password-Properties gesetzt haben sollten.
Die Methode öffnet die im URL angegebene Datenbank und liefert ein Objekt vom Typ Connection zurück.
getDriver(String)
Über die Methode kann derjenige Treiber gefunden werden, der den URL interpretieren kann.
getDrivers()
Die Methode liefert eine Liste aller registrierten Treiber zurück. Der Returnwert ist vom Typ Enumeration.
Der Name der Treiberklasse kann über d.getClass().getName() in Erfahrung gebracht werden, wobei d vom
Typ Driver ist.
14
Datenbanken



getLoginTimeout()
Die Treiber warten maximal eine bestimmte Anzahl von Millisekunden, bevor ein Verbindungsversuch als
erfolglos gewertet wird. Diese Methode liefert die Anzahl an Millisekunden zurück.
registerDriver(Driver)
Eine neu geladene Treiberklasse wird über diese Methode beim Treibermanager registriert.
setLoginTimeout(int)
Die Methode legt fest, wie lange (in Millisekunden) ein Treiber versucht, die Verbindung zur Datenbank
aufzubauen, bevor der Versuch als erfolglos gewertet wird.
4.2 Das Interface Connection
Eine Connection repräsentiert immer eine Sitzung mit einer spezifischen Datenbank. Jede Connection definiert
einen Kontext. Im Gültigkeitsbereich dieses Kontexts werden SQL-Anweisungen an eine Datenbank gesandt und
gegebenenfalls Ergebnismengen zurückgeliefert.
Weiterhin können über eine Connection Metadaten über die Datenbank erhalten werden.
Jede Connection ist per Default in den AutoCommit Modus geschaltet, d.h., daß jede Änderung des
Datenbestands sofort dauerhaft gültig wird.
Die Attribute einer Connection beziehen sich ausnahmslos auf die Transaction-Isolation, wie bereits im Kapitel
über Transaktionen besprochen wurde.
Die wichtigsten Methoden:









clearWarnings()
Die zuletzt von der Datenbank generierte Warnung wird auf null gesetzt, also gelöscht.
close()
Diese Methode schließt die Verbindung zur Datenbank sofort und gibt alle JDBC Sourcen frei.
commit()
Über den Aufruf dieser Methode wird ein expliziter COMMIT an die Datenbank gesandt, so daß alle
Änderungen am Datenbestand wirksam und eventuelle LOCKS entfernt werden.
createStatement()
Durch diesen Methodenaufruf wird für die aktive Datenbanksitzung ein Statement-Objekt generiert. Über
Instanzen von diesem Typ können SQL-Anweisungen ohne Parameter an die Datenbank übergeben werden.
getAutoCommit()
Der momentane AutoCommit-Status der Datenbank wird über diesen Aufruf abgefragt und bekanntgegeben.
getMetaData()
Eine Datenbank kann Informationen über ihre Tabellen, die unterstütze SQL-Grammatik, Stored Procedures
und viele weitere Möglichkeiten der aktuellen Verbindung bereitstellen.
getTransactionIsolation()
liefert den aktuellen Transaktions-Isolations-Modus.
getWarnings()
Die erste Warnung, die von der Datenbank generiert wurde, ist gecached und wird über diese Methode
abgerufen.
isClosed()
überprüft, ob die aktuelle Verbindung geschlossen ist.
15
Datenbanken






isReadOnly()
überprüft, ob die Verbindung nur Lesezugriff erlaubt.
prepareCall(String)
Diese Methode liefert ein Objekt vom Typ CallableStatement zurück. Der übergebene String ist in aller
Regel ein Aufruf einer StoredProcedure, deren Übergabeparameter mit einem ‚?‘ bekanntgemacht werden.
Die Definition des Strings ist im allgemeinen eine JDBC-Escape Sequenz. Durch das Vorbereiten eines
solchen Strings wird der Aufruf der StoredProcedure optimiert, da das CallableStatment eine vorkompilierte
Version der Anweisung beinhaltet.
rollback()
Alle kürzlichen Änderungen werden zurückgenommen. Die LOCKS auf Datensätzen oder Tabellen werden
entfernt.
setAutoCommit(boolean)
Der AutoCommit Status der Datenbank kann ein- oder ausgeschaltet werden.
setReadOnly(boolean)
Die Connection kann auf reinen Lesezugriff umgestellt werden.
setTransactionIsolation(int)
setzt das Transaction-Isolation Level auf den übergebenen Wert. Nähere Informationen zu den
Transaktionsstufen finden sich im Kapitel über Transaktionen.
4.3 Das Interface CallableStatement
CallableStatements erben Attribute und Methoden eines PreparedStatement. Über CallableStatements
werden Stored Procedures aufgerufen. Zu diesem Zweck wurde eine JDBC-Escape Sequenz definiert, die einen
Standard für solche Aufrufe, unabhängig vom RDBMS, zur Verfügung stellt.
Es gibt zwei verschiedene Arten der Syntax. Eine der beiden erwartet einen Rückgabewert, die andere nicht. Der
Ergebnisparameter muß als OUT-Parameter gekennzeichnet werden. Weiterhin existieren reine IN und ein
INOUT Parametertyp, der sowohl Ergebnis als auch Eingabeparameter sein kann. Die Parameterliste wird
sequentiell über Integer-Werte abgearbeitet. Der erste Parameter hat die Nummer 1.
Syntax der Escape Sequenzen:
{ ? = call [,, … ]}
{ call [,, … ]}
Um IN-Parameter zu setzen werden die vererbten set-Methoden aus PreparedStatement verwendet. Der Datentyp
eines OUT-Parameter muß noch vor der Ausführung der Stored Procedure registriert werden. Sie werden über
die get-Methoden des CallableStatements ausgelesen.
Die Ergebnismengen werden in Form von einem oder mehreren ResultSets zurückgeliefert, die über die von
Statement ererbten Methoden bearbeitet werden können. Anstatt die Werte eines OUT-Parameters zu
verarbeiten, sollte lieber auf das ResultSet zurückgegriffen werden, da dadurch höhere Portabilität erreicht wird.
Beispiel:
//CallableStatement erzeugen:
cstmt = con.prepareCall(„{call proc_2( ?, ?, ? )}“);
//Eingabeparameter setzen:
cstmt.setByte( 1, 100 );
cstmt.setLong( 3, 1234567890 );
//Ausgabeparameter mit JDBC-Datentypen anmelden:
cstmt.registerOutParameter( 2, Types.SMALLINT );
cstmt.registerOutParameter( 3, Types.INTEGER );
16
Datenbanken
//Datenbankprozedur ausführen:
cstmt.executeUpdate();
//Ausgabeparameter abrufen:
int I = cstmt.getInt(2);
long l = cstmt.getLong(3);“10
Der erste Parameter der gerufenen Stored Procedure ist ein reiner Eingabewert, der zweite ein reiner OUTParameter, während der dritte die INOUT Operation unterstützt. Der erste Übergabewert der get und registerMethoden bezieht sich auf den Index des Parameters im Aufruf der Stored Procedure.
Die wichtigsten Methoden:












10
getBigDecimal(int, int)
Liefert den Wert eines NUMERIC-Parameters als ein Objekt der Klasse java.math.BigDecimal. Der erste
Übergabeparameter ist die Nummer des Parameters im Aufruf der Stored Procedure, der zwite die Anzahl
der Nachkommastellen.
getBoolean(int)
Ein BIT-Parameter wird als Boolean zurückgeliefert. Der Übergabeparameter entspricht der Nummer des
Parameters in der Aufrufliste der Stored Procedure.
getByte(int)
Ein TINYINT-Parameter wird als Java-Byte zurückgegeben. Der Übergabeparameter entspricht dem Index
des OUT-Parameters, der an die Stored Procedure übergeben wird.
getBytes(int)
Liefert den Wert eines SQL BINARY oder VARBINARY-Parameters als Java byte[] Feld zurück. Auch
hier ist der Übergabewert in der Parameterliste der Index des OUT-Parameters der Stored Procedure.
getDate(int)
Der Wert eines SQL DATE wird als java.sql.Date object ausgelesen. Der Übergabeparameter gibt
Aufschluß über den Index des zu konvertierenden OUT-Parameters der Stored Procedure.
getDouble(int)
Ein DOUBLE Parameter wird als Java Double ausgegeben. Der Parameter ist wie üblich indiziert.
getFloat(int)
wandelt Float-Parameter in Java-floats um.
getInt(int)
Datenbank-Integers werden auf Java Integer gemapt.
getLong(int)
BIGINT-Parameter werden zu Java Long.
getObject(int)
konvertiert einen Parameter in ein Java Object.
getShort(int)
SMALLINT-Parameter entsprechen Java Short-Werten.
getString(int)
CHAR, VARCHAR und LONGVARCHAR werden nach Java String konvertiert. Über den Übergabewert
der Funktion kann auf den Index des Parameters in der Stored Procedure verwiesen werden.
Rainer Klute: JDBC in der Praxis, Addison-Wesley, S. 141
17
Datenbanken





getTime(int)
Ein SQL Time Parameter wird als java.sql.Time Object ausgelesen.
getTimestamp(int)
Der Wert eines SQL TIMESTAMP Parameters wird als java.sql.Timestamp Objekt zurückgegeben.
registerOutParameter(int, int)
Mit dieser Funktion muß vor der Ausführung einer Stored Procedure der java.sql.Type eines jeden OutParameters der Procedure explizit registriert werden (siehe Beispiel in der Interfacebeschreibung). Der erste
Übergabewert entspricht dem Index des Parameters in der Stored Procedure, der zweite enthält den
java.sql.Type Code.
registerOutParameter(int, int, int)
Diese Version der Methode wird für NUMERIC oder DECIMAL Parameter verwendet. Der erste
Übergabewert ist der Index des Parameters in der Stored Procedure, der zweite entweder
java.sql.Type.DECIMAL oder java.sql.Type.NUMERIC, der dritte gibt die Anzahl der Nachkommastellen
im Ausgabewert an.
wasNull()
Beim Aufruf einer Stored Procedure kann der Wert eines OUT-Parameters SQL-Null annehmen. Da es sich
dabei um einen undefinierten Zustand handelt, wird eine spezielle Behandlung dieses Falls notwendig. Die
wasNull() Methode überprüft, ob der Parameter den undefinierten Zustand angenommen hat.
4.4 Das Interface PreparedStatement
Eine SQL-Anweisung kann vorkompiliert, also präpariert, werden. Das Ergebnis dieses Vorgangs wird in einem
java.sql.PreparedStatement-Objekt abgelegt. Dieses Objekt kann nun verwendet werden, um diese SQLAnweisung mehrmals auf der Datenbank abzusetzen. Diese Statements sind parametrisiert und erwarten
Eingabewerte, die über die setXXX()-Methoden des Interface eingegeben werden können.
Dabei muß jeweils die set-Methode verwendet werden, die dem sql.Type entspricht, den der Parameter erwartet,
z.B. für SQL Integer muß setInt(…) verwendet werden.
Sollen bei der Eingabe explizite Konvertierungen Anwendung finden, wird die Verwendung der setObject()Methode mit dem Ziel eines SQL Typen empfohlen.
Die wichtigsten Methoden:





clearParameters()
Einmal gesetzte Parameter werden weiterhin im Speicher gehalten. Das Umsetzen eines Parameters löscht
den alten Wert implizit. Trotzdem kann es sinnvoll sein, die gehaltenen Resourcen durch Aufruf dieser
Methode sofort freizugeben.
execute()
Einige SQL-Anweisungen liefern mehrere Ergebnisse zurück. Solch komplexe Statements werden über die
Methode execute() bearbeitet, genauso wie einfachere Formen von Anweisungen von executeUpdate() und
executeQuery() verarbeitet werden.
executeQuery()
Eine vorkompilierte SQL-Anweisung wird abgesetzt und liefert ein ResultSet zurück.
executeUpdate()
führt eine SQL INSERT, UPDATE oder DELETE Anweisung auf der Datenbank aus.
setAsciiStream(int, InputStream, int)
Wenn ein sehr großer ASCII –Wert als Eingabe für einen LONGVARCHAR Parameter vorgesehen ist,
kann er über diese Methode als java.io.InputStream eingegeben werden.
JDBC liest alle Zeichen aus dem InputStream, bis der End-Of-File Eintrag erreicht ist. Notwendige
Konvertierungen werden vom Treiber automatisch durchgeführt.
18
Datenbanken
Der erste Parameter der setAsciiStream()-Methode ist der Index des Parameters im SQL-Statement, der
zweite ein Objkt vom Typ InputStream und der dritte die Anzahl der Bytes im Stream.














setBigDecimal(int, BigDecimal)
Setzt den Parameter auf einen BigDecimal Wert.
setBinaryStream(int, InputStream, int)
Auch bei sehr großen Binärwerten ist es möglich, die Eingabe in den LONGVARBINARY-Parameter über
einen java.io.InputStream durchzuführen.
Die Methode liest den Stream bis zum End-Of-File Zeichen. Der erste Methodenparameter ist der Index des
Eingabewerts im Statement, der zweite ein Objekt vom Typ java.io.InputStream und der dritte die Anzahl
der Bytes im Strom.
setBoolean(int, boolean)
Übergibt einen java Boolean Wert an die SQL-Anweisung.
setByte(int, byte)
Setzte einen Parameter auf einen Java Byte Wert.
setBytes(int, byte[])
Ein Parameter kann auch auf einen Array von Bytes gesetzt werden.
setDate(int, Date)
Die Methode setzt einen Parameter auf den Wert eines java.sql.Date.
setDouble(int, double)
übergibt einen Java double Wert an das SQL-Statement.
setFloat(int, float)
setzt einen Java float Wert ins Statement ein.
setInt(int, int)
übergibt einen Java int an die SQL-Anweisung.
setLong(int, long)
setzt einen long Wert.
setNull(int, int)
setzt einen Parameter auf SQL Null. Der zweite Übergabewert in der Liste enthält den SQL-Typen, der auf
SQL NULL gesetzt werden soll.
setObject(int, Object)
Setzt den Wert eines Parameters über den Umweg eines java Objects.
In der JDBC Spezifikation ist ein Mapping eines java Objects auf entsprechende SQL Typen vorgesehen.
Das Objekt wird konvertiert, bevor es an die Datenbank gesandt wird. Über diese Methode können
datenbankspezifische abstrakte Datentypen abgesetzt werden, indem man einen treiberspezifischen Java
Typen verwendet.
setObject(int, Object, int)
Diese Methode ist äquivalent zur bereits beschriebenen. Der dritte Parameter in der Liste entspricht dem
SQL-Zieltypen auf den abgebildet werden soll.
setObject(int, Object, int, int)
Auch diese Methodendefinition arbeitet analog. Abstrakte Datentypen werden im dritten Parameter als
java.sql.Types.OTHER angegeben, um datenbankspezifische abstrakte Datentypen zu mappen. Der vierte
Parameter gilt nur für NUMERIC und DECIMAL Werte. Er gibt die Anzahl der Nachkommastellen an.
19
Datenbanken





setShort(int, short)
übergibt einen Java short Wert an das Statement.
setString(int, String)
setzt den Parameter auf einen Java String.
setTime(int, Time)
der Parameter nimmt den Wert eines java.sql.Time Objektes an.
setTimestamp(int, Timestamp)
übergibt den Wert eines java.sql.Timestamp Objekts an das Statement.
setUnicodeStream(int, InputStream, int)
Sinnvollerweise übergibt man sehr große UNICODE Werte an einen LONGVARCHAR Parameter über
einen java.io.InputStream. Der Stream wird bis zum End-Of-File Delimiter gelesen. Der Treiber führt
automatisch notwendige Konvertierungen durch. Der dritte Übergabewert der Methode enthält die Anzahl
der Bytes im Strom.
4.5 Das Interface Statement
Dieses Interface verarbeitet einfache, statische SQL-Anweisungen und liefert die Ergebnismengen als ResultSet
zurück.
Nur ein einzelnes ResultSet kann pro Statement zur selben Zeit geöffnet sein. Sollen mehrere Ergebnismengen
gleichzeitig bearbeitet werden, muß für jedes ein separates Statement-Objekt zur Verfügung stehen. Sollte eine
der executeXXX()-Methoden aufgerufen werden, während bereits ein ResultSet existiert, wird dieses implizit
geschlossen.
Die wichtigsten Methoden:







cancel()
wird benutzt, um ausgehend von einem Thread das Statement eines anderen Threads abzubrechen, falls
dieses gerade ausgeführt wird.
clearWarnings()
Alle Warnungen, die von der Datenbank an den Treiber übergeben wurden, werden gespeichert. Eine neue
Warnung löscht implizit die alte, oder aber ein Aufruf dieser Methode setzt die Warnung auf null.
close()
Die close-Methode schließt explizit eine Datenbankverbindung und gibt die benötigten Resourcen frei. Dies
geschieht auch implizit bei Beendigung eines Programms. Trotzdem kann es sich als sinnvoll erweisen, den
Verbindungsabbau explizit durchzuführen.
execute(String)
Führt ein SQL-Statement aus, das mehrere Ergebnismengen produzieren kann.
executeQuery(String)
Führt eine SQL-Anweisung aus, die nur ein einzelnes ResultSet zurückliefert.
executeUpdate(String)
Führt ein SQL INSERT, UPDATE oder DELETE Statement auf der Datenbank aus.
getMaxFieldSize()
Das Limit maxFieldSize (in Bytes) gibt die maximale Anzahl der Daten an, die für einen Spaltenwert
zurückgegeben werden können. Dies trifft nur auf BINARY, VARBINARY, LONGVARBINARY, CHAR,
VARCHAR und LONGVARCHAR Attribute zu.
20
Datenbanken











getMaxRows()
Der Wert von maxRows zeigt an, wieviele Datensätze ein ResultSet maximal beinhalten kann.
getMoreResults()
navigiert zur nächsten Ergebnismenge innerhalb des Statements.
getQueryTimeout()
Der Timeout-Wert ist die Anzahl an Sekunden, die der Treiber maximal auf Ausführung eines Statements
wartet, bevor die Operation als erfolglos eingestuft wird.
getResultSet()
liefert das aktuelle Ergebnis als ResultSet zurück. Dies kommt z.B. zur Anwendung, wenn über die
execute()-Methode mehrere Ergebnismengen erzeugt wurden.
getUpdateCount()
liefert das aktuelle Ergebnis als Zähler zurück, der anzeigt, wieviele Datensätze von einer Änderung
betroffen waren. Wenn der Rückgabewert ein ResultSet ist, oder mehrere Ergebnisse vorliegen, wird –1
ausgegeben.
getWarnings()
liefert die erste Warnung, die bei Aufruf des Statements erzeugt wurde.
setCursorName(String)
gibt dem Cursor einen Namen, der bei weiteren Aufrufen der execute-Methoden des Statements verwendet
wird.
setEscapeProcessing(boolean)
Nur wenn diese Option eingeschaltet ist, ersetzt der Treiber SQL-Escape-Sequencen durch
Datenbanksyntax, bevor das Statement auf der Datenbank abgesetzt wird.
setMaxFieldSize(int)
Die maxFieldSize (in Byte) beschränkt die Größe der Daten, die für ein Attribut zurückgeliefert werden
können. Dies betrifft nur Datenfelder vom Typus BINARY, VARBINARY, LONGVARBINARY, CHAR,
VARCHAR und LONGVARCHAR.
setMaxRows(int)
limitiert die Anzahl der Datensätze, die ein ResultSet enthalten kann.
setQueryTimeout(int)
liefert die Anzahl der Sekunden, die der Treiber maximal auf die Ausführung eines Statements wartet.
4.6 Das Interface ResultSet
Die Ausführung eines Statements generiert eine Art virtuelle Tabelle, die in einem ResultSet abgespeichert ist.
Die Datensätze sind sequentiell angeordnet. Innerhalb eines Datensatzes kann in beliebiger Reihenfolge auf ein
Attribut positioniert werden.
Ein ResultSet stellt einen Cursor zur Verfügung, der auf den jeweils aktuellen Datensatz verweist. Nach der
Initialisierung des ResultSet steht dieser Cursor allerdings VOR dem ersten Datensatz. Mit der Methode next()
kann zum ersten Datensatz gesprungen werden.
Die Spalten in einem Datensatz können über den Index, beginnend bei 1, oder aber den Spaltennamen
angesprochen werden. Der Spaltenname wird case insensitive behandelt. Das Auslesen der Werte erfolgt über
eine Vielzahl von getXXX()-Methoden, entsprechend dem zu lesenden Datentypen. Diese Methoden führen
eine Konvertierung des datenbankspezifischen Datentyps in den zugehörigen Java-Typen durch.
Ein ResultSet wird vom ausführenden Statement geschlossen sobald das Statement geschlossen wird, wenn es
neu ausgeführt wird, oder aber wenn zur nächsten Ergebnismenge gesprungen wird, für den Fall daß mehrere
Ergebnismengen vorliegen.
21
Datenbanken
Der Index, die Typen und Eigenschaften der Spalten eines ResultSet können durch das ResultSetMetaDataObjekt abgefragt werden, das von der getMetaData()-Methode bereitgestellt wird.
Die wichtigsten Methoden:














clearWarnings()
Alle gespeichertern Warnungen für dieses ResultSet werden gelöscht und auf null gesetzt. Dies ändert sich
erst, wenn das RDBMS eine neue Warnung erzeugt.
close()
schließt explizit die Datenbank des ResultSets und gibt alle JDBC Resourcen frei. Dies kann unter
Umständen sinnvoller sein, als auf ein implizites Schließen der Datenbank zu warten.
findColumn(String)
liefert den Index einer Spalte im ResultSet anhand des Spaltennamens zurück.
getAsciiStream(int)
Ein Spaltenwert wird als Stream von ASCII Zeichen eingelesen und aus dem Strom heraus blockweise
verarbeitet.
getAsciiStream(String)
Ein Spaltenwert wird als Stream von ASCII Zeichen eingelesen und aus dem Strom heraus blockweise
verarbeitet.
getBigDecimal(int, int)
liest den Wert einer Spalte als java.lang.BigDecimal Objekt. Der zweite Übergabeparameter setzt die
Anzahl der Nachkommastellen fest.
getBigDecimal(String, int)
liest den Wert einer Spalte als java.lang.BigDecimal Objekt. Der zweite Übergabeparameter setzt die
Anzahl der Nachkommastellen fest.
getBinaryStream(int)
Ein Spaltenwert kann als uninterpretierter Strom von Bytes eingelesen und anschließend aus dem Strom
heraus blockweise verarbeitet werden.
getBinaryStream(String)
Ein Spaltenwert kann als uninterpretierter Strom von Bytes eingelesen und anschließend aus dem Strom
heraus blockweise verarbeitet werden.
getBoolean(int)
liefert den Spaltenwert als Java boolean zurück.
getBoolean(String)
liefert den Spaltenwert als Java boolean zurück.
getByte(int)
liefert ein Java byte.
getByte(String)
liefert ein Java byte.
getBytes(int)
liefert einen Array von Java bytes.
22
Datenbanken

















getBytes(String)
liefert einen Array von Java bytes.
getCursorName()
gibt den Namen des Cursors aus, der von diesem ResultSet verwendet wird.
getDate(int)
Der Spaltenwert wird als java.sql.Date Objekt ausgelesen.
getDate(String)
Der Spaltenwert wird als java.sql.Date Objekt ausgelesen.
getDouble(int)
liefert einen Java double.
getDouble(String)
liefert einen Java double.
getFloat(int)
liefert den Spaltenwert des aktuellen Datensatzes als Java float.
getFloat(String)
liefert den Spaltenwert des aktuellen Datensatzes als Java float.
getInt(int)
liefert den Spaltenwert des aktuellen Datensatzes als Java int.
getInt(String)
liefert den Spaltenwert des aktuellen Datensatzes als Java int.
getLong(int)
liefert den Spaltenwert des aktuellen Datensatzes als Java long.
getLong(String)
liefert den Spaltenwert des aktuellen Datensatzes als Java long.
getMetaData()
Spaltenindex, Typen und Eigenschaften der Spalten eines ResultSets können über ein Objekt vom Typ
ResultSetMetaData abgefragt werden, das von dieser Methode erzeugt wird.
getObject(int)
liefert den Spaltenwert des aktuellen Datensatzes als Java object.
getObject(String)
liefert den Spaltenwert des aktuellen Datensatzes als Java object.
getShort(int)
liefert den Spaltenwert des aktuellen Datensatzes als Java short.
getShort(String)
liefert den Spaltenwert des aktuellen Datensatzes als Java short.
23
Datenbanken











getString(int)
liefert den Spaltenwert des aktuellen Datensatzes als Java String.
getString(String)
liefert den Spaltenwert des aktuellen Datensatzes als Java String.
getTime(int)
liefert den Spaltenwert des aktuellen Datensatzes als java.sql.Time Objekt.
getTime(String)
liefert den Spaltenwert des aktuellen Datensatzes als java.sql.Time Objekt.
getTimestamp(int)
liefert den Spaltenwert des aktuellen Datensatzes als java.sql.Timestamp Objekt.
getTimestamp(String)
liefert den Spaltenwert des aktuellen Datensatzes als java.sql.Timestamp Objekt.
getUnicodeStream(int)
Ein Spaltenwert kann als Strom von UNICODE Zeichen eingelesen werden und wird dann aus dem Strom
heraus blockweise verarbeitet.
getUnicodeStream(String)
Ein Spaltenwert kann als Strom von UNICODE Zeichen eingelesen werden und wird dann aus dem Strom
heraus blockweise verarbeitet.
getWarnings()
Die erste Warnung beim Aufruf dieses ResultSets wird ausgegeben.
next()
Der Cursor auf den aktuellen Datensatz im ResultSet wird sequentiell weitergeschaltet. Bei Initialisierung
des ResultSets steht der Cursor VOR dem ersten Datensatz. Durch Aufruf dieser Methode wird auf die erste
gültige Reihe positioniert.
wasNull()
Ein Spaltenwert kann als Ergebnis SQL NULL enthalten. Dies bedeutet einen undefinierten Zustand. Über
die Methode wasNull() kann in Erfahrung gebracht werden, ob ein Spaltenwert diesen Zustand angenommen
hat.
5. Besonderheiten des JDBC-Treibers von Oracle
Da für jedes Datenbanksystem proprietäre JDBC-Treiber existieren, besitzen diese Treiber Eigenschaften, die
speziell auf dieses DBMS zugeschnitten sind.
Die Oracle JDBC Treiber unterstützen JDBC 1.22, die Version die mit dem JDK 1.1.1 ausgeliefert wird und
auch als Add-On für JDK 1.0.2 verfügbar ist.
Weiterhin werden alle SQL-Datentypen unterstützt, die von diesem Standard verlangt werden. Zusätzlich dazu
unterstützt der Treiber die oraclespezifischen Datentypen ROWID und REFCURSOR.
Datentypen
Folgende Tabelle zeigt, wie die JDBC-Typecodes auf Oracletypen gemappt werden.
JDBC-Typecodes
Types.CHAR
Types.VARCHAR
Types.LONGVARCHAR
Oracle Datentypen
CHAR
VARCHAR2
LONG
24
Datenbanken
Types.VARBINARY
Types.LONGVARBINARY
Alle numerischen Datentypen
Alle Datumstypen
RAW
LONG RAW
NUMBER
DATE
Abb. 3: Mapping von Java Typecodes auf Oracle
Weiterhin wird folgendes Oracle-spezifisches Mapping durchgeführt:
Oracle Type Code
OracleTypes.ROWID
OracleTypes.REFCURSOR
Oracle Datentypen
ROWID
REFCURSOR
Abb. 4: Mapping von speziellen Datentypen
Die ROWID wird als Java String und der REFCURSOR als ResultSet zurückgegeben.
Multibyte Character Sets
Die Thin-Version des Treibers von Oracle kann jede Datenbank, völlig ungeachtet des in der Datenbank
verwendeten Character Sets, ansprechen. Dies wird dadurch erreicht, daß alle Zeichen in Unicode 1.2
umgewandelt werden. Da Java selbst Unicode 2.0 verwendet, entstehen Probleme nur für die koreanische
Schrift.
Streaming
Der JDBC-Treiber unterstützt Streaming in beide Richtungen zwischen Client und Server. Alle StreamKonvertierungen, BINARY, ASCII und UNICODE, werden zur Verfügung gestellt.
Stored Procedures
Stored Procedures und anonymous Blocks werden von der Thin-Version des Treibers voll unterstützt. Hierfür
kann sowohl der Standard der SQL92 Escape Sequenzen verwendet werden, als auch die speziellen Oracle
Escape-Sequenzen.

SQL92 Syntax:
CallableStatement cs1 = conn.prepareCall ( "{call proc (?,?)}" ) ;
CallableStatement cs2 = conn.prepareCall ( "{? = call func (?,?)}" ) ;

Oracle Syntax
CallableStatement cs3 = conn.prepareCall ( "begin proc (:1, :2); end;" ) ;
CallableStatement cs4 = conn.prepareCall ( "begin :1 := func(:2,:3); end;" ) ;
Metadaten
Alle Standardmethoden zur Abfrage von Metadaten sind implementiert. Zu diesem Zweck werden Abfragen auf
die Metadaten-Tabellen des RDBMS durchgeführt. Zudem enthält die vertriebene Version des Treibers den
Sourcecode der Klasse OracleDatabaseMetadata, so daß eigene Methoden und Methodenaufrufe generiert
werden können.
SQL92 Syntax
SQL92 Escape-Sequenzen werden voll unterstütz, bis auf den Gebrauch von „Outer Joins“.
Prefetching von Reihen
25
Datenbanken
In einer Abfrage kann angegeben werden, wieviele Reihen auf einmal in der Abfrage zum Client übertragen
werden sollen. Die Defaulteinstellung ist 10. Durch diese Option werden Round Trips zum Server reduziert. Die
Anzahl der „vorbestellten“ Reihen kann entweder für die Connection oder für das Statement festgelegt sein.
Batching von Statements
Der JDBC-Treiber erlaubt es, mehrere Inserts und Updates im Client anzusammeln und dann via Batch an den
Server zu schicken. Dadurch werden wiederum Round Trips zum Server vermieden. Die Batchsize kann für ein
Statement eingestellt werden (Defaulteinstellung ist 1).
Vordefinition von Spalten einer Abfrage
Es ist möglich, den Server schon vor der Ausführung einer Abfrage über die notwendigen Datentypen zu
informieren. Dadurch werden Round Trips zum Server vermieden.
Einschränkungen des Treibers
Einige Anforderungen des JDBC 1.22 Standards werden vom Treiber nicht erfüllt:
CursorName
Aufrufe der Methoden getCursorName() und setCursorName() können vom Treiber nicht unterstützt werden, da
sie nicht auf die existenten Oracle-Konstrukte gemappt werden können. Oracle setzt deshalb die Verwendung
von ROWID verbindlich fest.
SQL92 Outer Join Escapes
Die Syntax für solche Sequenzen wird nicht unterstützt. Stattdessen muß die Oracle Syntax („+“) verwendet
werden.
PL/SQL BOOLEAN und RECORD Typen
Der Treiber untertützt diese Datentypen weder als IN noch als OUT Parameter von PL/SQL
Anweisungsblöcken. Ein möglicher Workaround wäre z.B die Definition einer zweiten Stored Procedure, die
den BOOLEAN-Wert als NUMERIC oder CHAR-Wert akzeptiert und an die erste Procedure als BOOLEAN
weiterreicht.
IEEE 754 Floating Point Kompatibilität
Die arithmetischen Operationen der NUMBER-Datentypen von Oracle sind nicht mit denen der IEEE
Spezifikation kompatibel. Dadurch können Abweichungen in den Ergebnissen der Berechnung einer OracleDatenbank und der selben Berechnung durch ein Java Programm auftreten.
Oracle speichert Zahlen in einem Format, das zur Dezimalarithmetik kompatibel ist und stellt 38 Dezimalzahlen
als Präzision zur Verfügung. 0, negativ unendlich und positiv unendlich werden exakt dargestellt. Für jede
positive Zahl existiert eine exakte negative Repräsentation des Betrags. Jede positive Zahl zwischen 10 -38 und (110-38)*10126 werden mit der vollen Präzision abgebildet.
JDBC OCI Features
Die JDBC OCI Treiber sind Treiber vom Typ2, die native Methoden von Java verwenden, um die C
Einsprungpunkte der OCI Bibliothek anzusprechen. Aus diesem Grund ist dieser Treiber nicht mehr
plattformunabhängig.
Diese Treiber existieren für Windows, Solaris und noch einige andere Plattformen.
OCI Treiber können nicht für Applets verwendet werden, die auf unbekannten Systemumgebungen gestartet
werden. Sie eignen sich jedoch hervorragend für reine Java Applikationen oder zur Verwendung im
Dreischichtenmodell mit einer Java-Schicht als Middleware.
Für diese Treiber muß clientseitig eine SQL*Net Version 2.3 oder höher installiert werden. Da als Schnittstelle
das Oracle Call Interface verwendet wird, können diese Treiber für alle SQL*Net-Adapter verwendet werden,
IPC, Named Pipes, TCP/IP, DECnet und noch einige mehr. Weiterhin können alle Features der Advanced
Networking Option, z.B. verschlüsseltes SQL*Net, in vollem Umfang genutzt werden.
26
Datenbanken
Die OCI Treiber konvertieren CHAR Daten aus dem Multibyte Character Set in Java Unicode Zeichen. Dies
wird clientseitig über die OCI Routinen durchgeführt.
JDBC Thin Features
Dieser Treiber ist zu 100% vom Typ4. Er verbindet sich direkt mit Oracle über einen Java Socket, ohne
javaspezifische Middleware zu benötigen. Die Verbindung kommt nur dann zustande, wenn ein TNS Listener
existiert, der TCP/IP Sockets nach Aufrufen „abhorcht“.
Der Thin Treiber ist nur soweit plattformspezifisch, wie dies für Java selbst zutrifft. Jedes System, auf dem eine
korrekte Implementierung von Java zur Verfügung steht, kann diesen Treiber verwenden.
Der Treiber wird als Teil der Applikation oder des Applets in jeden Browser „down“ geloaded. Die Verwendung
solcher Treiber kann allerdings durch Firewalls eingeschränkt sein.
Bekannte Bugs
Die Methoden getQueryTimeout(), setQueryTimeout() und cancel() können den Treiber während der Ausführung
eines Statements zum Absturz bringen.
Der Oracle OCI Treiber arbeitet derzeit noch nicht mit den Entwicklungsumgebungen Symantec Visual Café
oder Microsoft Visual J++ zusammen.
27
Herunterladen