79
THEMA: JDBC/SQL Vortrag: Pascal Gbodogbe am 14.6.2001 TEIL_1: SQL & TEIL_2: JDBC

THEMA: JDBC/SQL Vortrag: Pascal Gbodogbe am 14.6.2001

Embed Size (px)

DESCRIPTION

THEMA: JDBC/SQL Vortrag: Pascal Gbodogbe am 14.6.2001. TEIL_1: SQL & TEIL_2: JDBC. Einführung:. Durch die Einführung der JDBC-Vorlesung können wir merken: *JDBC stellt eine standarisierte Methode zum Zugriff auf Datenbanken aus Java-Programmen zur Verfügung. - PowerPoint PPT Presentation

Citation preview

THEMA: JDBC/SQLVortrag: Pascal Gbodogbe am 14.6.2001

TEIL_1: SQL & TEIL_2: JDBC

Einführung:

Durch die Einführung der JDBC-Vorlesung können wir merken:

*JDBC stellt eine standarisierte Methode zum Zugriff auf Datenbanken aus Java-Programmen zur Verfügung.

*JDBC enthält die Möglichkeiten:– Um Verbindungen zu Datenbanken zu öffnen und zu

schließen,– Um SQL-Anweisungen an Datenbanken zu schicken– und um die Antworten entgegenzunehmen und deren

Auswertung im Java-Programm zu ermöglichen.

JDBC baut vollständig auf SQL auf. SQL "Standard Query Language". Die Kommunikation zwischen dem Java-Pro-

gramm und der Datenbank erfolgt über SQL-Anweisungen. Diese werden als Text an die Datenbank geschickt, die daraufhin als Antwort die Ergebnisse zurückschickt. Die SQL-Anweisungen werden nicht vom Java-Compiler auf Korrektheit geprüft. Fehler können also erst durch die Datenbank festgestellt werden.

Bevor wir in Detail bei JDBC gehen , wollen wir SQL in Überblick sehen.

TEIL_1: SQL

SQL - ein Überblick Unser Überblick ist unterteilt in :

- Tabellendeklaration in SQL,

- Anfragen in SQL,

- Änderungsoperationen in SQL, und

- Definition von Sichten in SQL

Tabellendeklaration in SQL:

Bei der Deklaration einer Tabelle müssen folgenden Punkte festgelegt werden:

* Attribute als Namen der Spalten,

* Wertebereiche als Angaben von Datentypen für die Einträge in Spalten,

* Relationenschemata als Typdefinitionen von Tabellen,

* Schlüssel zur Festlegung eindeutiger Identifikatoren für Tupel in Tabellen, und

* die Deklaration von Fremdschlüssel zur Erzwingung der referentiellen Integrität bei Verweisen

auf Einträge in anderen Tabellen.

Die Sprache zur Festlegung von Datenbankbeschreibungen nennt man database definition language, kurz DDL. Die Tabellendeklaration in SQL sieht der Definition von Record-Strukturen in Programmiersprachen nicht unähnlich, erweitert diese aber um die RDBMS-spezifischen Aspecte. Folgende Beispieldeklaration zeigt den prinzipiellen Aufbau:

CREATE TABLE book (

isbn VARCHAR ( 30 ) NOT NULL,

title VARCHAR ( 50 ) ,

price FLOAT ); Wertebereiche für Attribute: Die Möglichen Werte-

bereiche für Attribute sind die Datentypen:

* integer (oder auch integer4, int ),

* smallint (oder auch integer2),

* float (p) (oder auch kurz float),

* decimal ( p , q ) und numeric ( p , q ) mit jeweils q Nachkommastellen,

* character (n) (oder kurz char(n), bei n = 1 auch char ) für Strings fester Länge n,

* character varying (n)(oder kurz varchar(n) ) für Strings variabler Länge bis zur Maximallänge n,

* bit (n) oder bit varying (n) analog für Bitfolgen und

* date, time bzw. timestamp für Datums-, Zeit- und kombinierte Datums-Zeit-Angaben.

BLOB und CLOB: Eine weitere Neuerung im Standard sind die sogenannten large object-Datentypen BLOB und CLOB. BLOB steht für binary large object; CLOB für

charater large object. Die Werte entsprechender Daten-

typen sind ( in der Regel sehr lange ) Folgen von Binär-

werten ( bei einem BLOB ) oder von Character-Zeichen (CLOB), wie sie zum Beispiel bei der Abspeicherung eines digitalisierten Photos oder eines unstrukturierten Textes entstehen.

Nullwerte: Mit der Klausel NOT NULL können in bestimmten Spalten Nullwerte als Attributwerte ausge-

schlossen werden. Primärschlüssel: Das folgende Beispiel zeigt die

Definition von identifizierenden Schlüsseln ( in SQL als Primärschlüssel bezeichnet: derjenige von mehreren möglichen Schlüsseln, der vom System genutzt und kontrolliert wird) und Fremdschlüsselbeziehung:

CREATE TABLE book (

isbn VARCHAR ( 30 ) NOT NULL,

title VARCHAR ( 50 ) ,

price FLOAT

publ_id INTEGER ,

PRIMARY KEY ( isbn ) ,

FOREIGN KEY publ_id REFERENCES (publisher) ); Anfragen in SQL: Eine erste SQL-Anfrage an eine

einzelne Tabelle könnte wie folgt lauten:

SELECT title , price

FROM book

WHERE isbn = ‘ 3 - 929821 - 31 - 1 ‘ ;

Diese Anfrage gibt die Relation an, aus der Daten gewonnen werden sollen ( hinter FROM ), sowie eine

Selektionsbedingung und die Attribute einer Projektion. Die Angaben der Selektionsbedingung können wie gewohnt durch boolesche Operatoren verbunden werden, die als englische Worte notiert werden (AND, OR und NOT). Als Basisprädikate sind insbesondere die bekannten Vergleichsprädikate erlaubt.

Duplikatunterdrückung:

SQL hat eine Multimengensemantik; die Duplikatunter-

drückung muß also explizit erzwungen werden, wenn sie erwünscht ist:

SELECT DISTINCT lastname

FROM author; Kreuzprodukt: Als wesentliche Möglichkeit, Daten aus zwei

Relationen miteinander zu verknüpfen, nutzt SQL das Kreuzprodukt, und nicht den natürlichen Verbund. Die

folgende Anfrage berechnet also das Kreuzprodukt zweier Relationen, wobei die Angabe * die Ausgabe aller Attribute erwirkt:

SELECT *

FROM book, publisher; Verbundbedingungen in SQL:

Der ( eigentlich erwünschte) Verbund muß durch die Angabe einer Verbundbedingung erzwungen werden. Hierzu müssen gleichlautende Attribute des Kreuz-

produktes unterschieden werden - einen expliziten Umbe-

nennungsoperator für Zwischenergebnisse wie in der Relationenalgebra kennt SQL nicht. Dies erfolgt über sogenannte Tupelvariablen, die im Standardfall aus den Namen der Relationen abgeleitet werden:

SELECT *

FROM book , publisher

WHERE book . Publ_id = publisher . Publ_id; Selbstverbund: Natürlich können auch neue Variablen-

namen generiert werden - bei Selbstverbunden ist dies sogar notwendig, wie folgende Anfrage zeigt, die die ISBN von Büchern berechnet, die von zwei Autoren gemeinsam geschrieben wurde:

SELECT ba1 . isbn

FROM book_author ba1 , book_author ba2

WHERE ba1 . isbn = ba2 . isbn AND

ba1 . a_id = 3 AND

ba2 . a_id = 4;

In der letzten Standardisierungsversion SQL-92 wurden

auch explizite Verbundoperatoren eingeführt. So berechnet die folgende Anfrage tatsächlich den natürlichen Verbund:

SELECT *

FROM book NATURAL JOIN publisher;

Üblich ist aber in SQL-Anwendungen noch die vorher beschriebene Variante, die dem ersten SQL-Standard entspricht. Die erste Variante wird auch von allen RDBMS unterstützt, was beim SQL-92-Standard nicht automatisch im vollem Umfang der Fall ist.

Vereinigung und Differenz in SQL: Der Algebraoperator Vereinigung wird in SQL explizit mit UNION notiert. Der Differenzbildung hingegen wird in der Regel durch geschachtelte Anfragen realisiert, wie folgendes Beispiel zeigt:

SELECT *

FROM customer

WHERE customer . cust_id NOT IN (

SELECT cust_id

FROM book_order );

Da geschachtelte Unteranfragen etwas komplexer in der Semantik und den Syntaktischen Varianten sind, belassen wir es an dieser Stelle mit diesem einfachen Beispiel.

Aggregierung:

* Die Aggregatfunktionen COUNT, SUM, AVG, MAX und MIN erlauben es, aggregierte Werte für Spalten zu bilden.

Gruppierung:

* Die Gruppierung mittels GROUP BY und HAVING

gruppiert Tupel in einer Relation und erlaubt die Bildung eines aggregierenden Resultats für jede Gruppe.

Sortierung: Die Angabe von ORDER BY sortiert ein Anfrageergebnis.

Änderungsoperationen in SQL

In SQL werden die folgenden Änderungsoperationen unterstützt:

* Die INSERT-Anweisung ermöglicht das Einfügen eines oder mehrerer Tupel in eine Basisrelation oder Sicht.

* Mittels UPDATE können ein oder mehrere Tupel in eine Basisrelation oder Sicht geändert werden.

* Die DELETE-Anweisung realisiert das Löschen eines oder mehrerer Tupel aus einer Basisrelation oder Sicht.

Die INSERT-Anweisung: Für das Einfügen mittels

INSERT kann man zwei Varianten unterscheiden. In der ersten Variante werden konkrete Werte in eine Tabelle eingetragen:

INSERT

INTO publisher (publ_id , name)

VALUES (1 , ‘ dpunkt - Verlag ‘ ) ;

Die Angabe der Attribute hinter dem Tabellenname ist notwendig, wenn nicht alle Attribute gesetzt werden sollen und die restlichen mit Nullwerten gefüllt werden sollen.

In der zweiten Variante werden die einzufügenden Tupel mittels einer Anfrage berechnet:

INSERT INTO publisher (publ_id , name)

( SELECT id, name FROM company ) ;

Die UPDATE-Anweisung: Die Attributwertänderung mittels UPDATE entspricht dem Zuweisungsoperator aus Programmiersprachen ( so kann der alte Wert zur Berechnung des neuen genutzt werden).

UPDATE book

SET price = price * 0.9

WHERE stock < 10;

Mehrere Attribute einer Tabelle können gleichzeitig gesetzt werden.

Die DELETE-Anweisung: Bei der Löschoperation kann neben der Angabe der Tabelle eine qualifizierende Bedin-

gung angegeben werden, die die zu löschenden Tupeln festlegt:

DELETE FROM book_order

WHERE status = 1;

Definition von Sichten in SQL: Sichtdefinition in SQL: In SQL wird die Sichtdefinition

durch die Schlüsselwörter CREATE VIEW, gefolgt vom Namen der Sicht, eingeleitet. Nach dem Sichtnamen steht im einfachsten Fall das Schlüsselwort AS und eine SQL-Anfrage, die die Sicht definiert (optionale Teile sind in eckige Klammern gesetzt):

CREATE VIEW SichtName

[ SchemaDeklaration ]

AS SQLAnfrage

[ WITH CHECK OPTION ]

Das Relationenschema der Sicht, also Name und Datentyp der einzelnen Spalten, wird aus der Anfrage abgeleitet und muß nicht explizit angegeben werden. Allerdings kann optional eine SchemaDeklaration hinter dem Sichtnamen

eingefügt werden, in der die Namen der Spalten festgelegt werden können. Dieses Sprachkonstrukt erlaubt auch die Umbenennung von Spalten.

WITH CHECK OPTION: Ein weiterer optionaler Teil

einer Sichtdeklaration ist die Angabe der Schlüsselwörter WITH CHECK OPTION am Ende der Sichtdefinition. Diese Angabe legt fest, ob Änderungen der Sicht, die den in ihr nicht sichtbaren Teil der Datenbank beeinflussen, in einem Test erkannt und abgewiesen werden sollen.

Das folgende Beispiel zeigt eine Sichtdeklaration in SQL:

CREATE VIEW book_info AS

SELECT b . isbn, b . title, b . price ,

a . lastname , a . firstname , p . name

FROM book b , book_author ba ,

author a , publisher p

WHERE b . isbn = ba . isbn AND

ba .a_id = a . a_id AND

b . publ_id = p . publ_id; Änderungsoperationen auf Sichten: Soll eine Änderung

auf einer Sicht in Änderungen auf der Basisdatenbank umgesetzt werden, müssen eine Reihe von notwendigen oder wünschenswerten Kriterien eingehalten werden:

* Effektkonformität: Der Benutzer, der die Änderung auf der Sicht formuliert, soll nach der ausgeführten Änderung auf der Basisdatenbank im nächsten Zustand eine Ausprägung der Sicht erhalten, die dem Effekt entspricht, als wäre die Änderung auf der Sichtrelation direkt ausge-

führt worden. Dieses Kriterium fordert in gewissem Sinne die Korrektheit der Transformation.

* Minimalität bei Sichtäderungen: Die Basisdatenbank sollte nur minimal geändert werden, um den erwähnten Effekt zu erhalten.

* Konsistenzerhaltung bei Sichtänderungen:

Die Änderung einer Sicht darf zu keinen Integritätsverlet-

zungen der Basisdatenbank führen.

* Zugriffskontrolle bei Sichtänderungen: Wird die Sicht aus Gründen der Zugriffskontrolle eingeführt, darf der bewußt ausgeblendete Teil der Basisdatenbank von Änderungen der Sicht nicht betroffen werden.

* Zugriffsrechte: In SQL-Datenbanken wird eine einfache Modellierung von Zugriffsrechten auf Datenbestände unterstützt. Dabei haben Zugriffsrechte den folgenden Aufbau (Subjekt, Objekt, Aktion):

(AutorisierungsID, DB-Ausschnitt, Operation)

Die einzelnen Punkte haben die folgende Bedeutung:

* Autorisierungsidentifikator: (kurz AutorisierungsID) ist eine interne Kennung eines>>Datenbankbenutzers<<. Eine Typische AutorisierungsID kann die Benutzerkennung des Betriebssystems sein. Andere Beispiele wären Kennungen von Zugreifenden Softwaresystemen oder auch Kennungen von Benutzergruppen.

* Datenbank-Ausschnitte sind im Relationenmodell

gespeicherte Relationen und Sichten, aber auch ganze Datenbanken oder Schemainformationen.

* Unter den Operationen sind insbesondere die klassischen Operationen des Lesens, Einfügens, Änderns und Löschens von Datensätzen zu verstehen. Je nach konkret realisiertem System kommen weitere Operationen beispielsweise zur Verwaltung von Systeminformationen (etwa der Datenver-

teilung) hinzu.

* Rechtevergabe mittelsGRANT: Im SQL-Standard werden Rechte mittels der GRANT-Anweisung vergeben, die nach folgendem Muster notiert wird:

GRANT Rechte

ON Tabelle

TO BenutzerListe

[WITH GRANT OPTION]

Ein Spezialfall der Angabe eines AutorisierungsIDs ist die Angabe PUBLIC.

* Trigger: Ein Trigger besteht im wesentlichen aus der Angabe eines Auslösers und der Angabe von auszuführen-

den Folgeactionen:

CREATE TRIGGER . . .

ON Opreation : ( Anweisungen );

Als Beispiel für den Einsatz von Triggern betrachten wir die Realisierung eines berechneten Attributs durch Trigger. Das Beispiel basiert auf zwei Relationen, der Relation customer mit einem zusätzlichen Attribut num_orders für die Anzahl der Aufträge und einer zweiten Relation book_order. Der Wert des Attributs num_orders soll vom System verwaltet werden. Hierzu definieren wir einen Trigger wie folgt:

CREATE TRIGGER OrderCounter

ON INSERTION OF book_order o:

UPDATE customer

SET num_orders = num_order + 1

WHERE cust_id = NEW o . Cust_id;

Neben dem vorgestellten syntaktischen Grundgerüst der Definition von Triggern sind weitere Angaben möglich,

die insbesondere den Zeitpunkt der Triggeraktivierung betreffen:

* Zeitpunkt der Aktivierung von Trigger:

Mittels IMMEDIATE bzw. DEFERRED kann der Zeitpunkt der Aktivierung desTriggers festgelegt werden: sofort nach

der aktivierenden Operation oder am Ende der Transaktion. Aktuelle Implementierungen unterstützen oft nur den IMMEDIATE-Modus.

Die Angabe FOR EACH ROW aktiviert den Trigger für alle Einzeländerungen einer mengenwertigen Änderung separat.

Die Angaben BEFORE und AFTER steurn etwa in der aktuellen Version des kommerziellen Systems Oracle, ob der Trigger direkt vor oder nach einer Änderung aktiviert wird.

Mit REFERENCING NEW AS bzw. REFERENCING OLD AS kann eine Tupelvariable an die neu eingefügten bzw. gerade gelöschten (>>alten<<) Tupel einer Relation gebunden werden. Diese >>neuen<< bzw. >>alten<< Tupel werden auch als Elemente der sogenannten Differenzrelation bezeichnet.

TEIL_2: JDBC

JDBC: Java DataBase Connectivity Das JDBC-Package stellt eine vollständige Schnittstelle

zu SQL-Datenbanken zur Verfügung und erlaubt damit den Einsatz von Java-Programmen und Java-Applets (Applet ist eine Bezeichnung für ein Java-Progamm, das in eine HTML-Seite integriert ist.) als Front-Ends für kommerzielle Applikationen.

JDBC erfordert die direkte Nutzung von SQL-Anweisun-gen (Low-Level-API (Application Programmer Interface) )

JDBC besteht einer Menge von Klassen und Schnittstellen, die im Java-Package java . sql zusammengefaßt sind. Die wichtigsten Klassen und Schnittstellen sind hierbei:

java . sql . DriverManager: bildet den Einstiegspunkt, in-

dem über diese Klasse Treiber registriert und Verbindun-

gen zur Datenbank aufgebaut werden können. Java . sql . Connection: repräsentiert eine Datenbankver-

bindung. Java . sql . Statement: ermöglicht die Ausführung von

SQL-Anwendungen über eine gegebene Verbindung. Java . sql .ResultSet: verwaltet die Ergebnisse einer Anfra-

ge in Form einer Relation und unterstützt den Zugriff auf einzelne Spalten.

JDBC am Beispiel Ablauf einer JDBC-Anwendung Um die verschiedenen Aspekte der JDBC-Programmie-

rung einzugehen, wollen wir uns mit einigen kurze Beis-

piele befassen. Diese Programmausschnitte sollen die An-wendung der wichtigsten Klassen demonstrieren und gleichzeitig illustrieren, wie die Benutzung von JDBC ist. Der prinzipielle Ablauf einer JDBC-Datenbankanwen-dung umfaßt die folgenden Schritte:

1. Aufbau einer Verbindung zur Datenbank

2. Senden einer SQL-Anweisung

3. Verarbeiten der Anfrageergebnisse

Explizites Laden

Voraussetzung für den Aufbau einer Datenbankverbindung

ist das Laden eines geeigneten Treibers. Hierzu werden in

JDBC zwei Varianten unterstützt. Zum einen kann der

Treiber (d.h. die Java-Klasse des Treibers) explizit im Pro-

gramm geladen werden:

Class . forName( “ oracle . jdbc . driver .OracleDriver “); Automatisches Laden

Bei der zweiten Variante wird eine Liste von Treibern, je-

weils getrennt durch doppelpunkt, in der Systemeigen-

schaft ( Property ) sql . drivers festgelegt, die vom Treiber-

manager beim Start automatisch geladen werden. In bei-

den Fällen müssen sich die Treiber nach dem Laden selbs-

tändig beim Treibermanager registrieren.

Verbindungsaufbau

Der nächste Schritt ist der Verbindungsaufbau. Hierfür stellt der Treibermanager, d. h. die Klasse Java . sql . Dri-

verManager, eine eigene Methode getConnection bereit.

Als Argument dieser Methode muß eine URL (Uniform

Resource Locator)angegeben werden, die den Verbindungs

mechanismus und damit den zu verwendenden Treiber be-zeichnet. Zusätzlich sind noch Benutzername und Pass-

wort zu übergeben. Der Aufruf der Methode liefert im Erfolgsfall ein Connection-Objekt.

Connection con;

String url =

“ jdbc:oracle:thin:@antarctica:1521:mydb “ ;

con = DriverManager . getConnection (url , “tux“ ,

“ pingus “ );

Mit dem Connection-Objekt kann nun eine SQL-Anwei-

sung erzeugt werden. Wir wollen zunächst eine einfache

Anfrage betrachten, die mit executeQuery ausgeführt wird.

String query = “ SELECT title, price, “ + “ stock FROM book “;

Statement stmt = con.createStatement ( ) ;

ResultSet rs = stmt .executeQuery ( query); Ausführung von Anfragen

Die executeQuery-Methode liefert ein ResultSet-Objekt, das

die Ergebnisse der Anfrage verwaltet. Die Navigation über

die Ergebnismenge erfolgt nach dem Cursor-Prinzip. Die

Ergebnismenge kann als eine Tabelle angesehen werden,

auf die zunächst zeilenweise und dann spaltenweise zuge-

griffen werden kann. In JDBC existiert jedoch kein expli-ziter Cursor, vielmehr wird die aktuelle Position in der Er-

gebnismenge vom ResultSet intern verwaltet. Zum Weiter-

setzen des Cursors wird die Methode next verwendet. Diese Methode liefert so lange den Wert true, bis das Tabellen-

ende erreicht ist. Außerdem ist zu beachten, daß der ResultSet -Cursor zu Beginn vor dem ersten Tupel posi-

tioniert ist, d.h., bevor ein Tupel gelesen werden kann, muß die Methode next aufgerufen werden.

Zugriff auf Spalten

Nachdem der Cursor positioniert ist, können die Spalten-

werte des aktuellen Tupels ausgelesen werden. Hierfür ste-

hen eine Reihe von getXXX-Methoden für die verschiede-

nen Datentypen und die korrespondierenden Java-Typen zur Verfügung. So heißt die Methode zum Lesen einer Zei-

chenkette beispielsweise getString, wobei der Attributtyp

der Relation hier VARCHAR und der Java-Typ des Ergeb-

nisses java .Lang . String ist. Der Zugriff auf eine konkre-

te Spalte der Ergebnisrelation mit Hilfe der getXXX-Metho-

den erfolgt entweder über den Index der Spalte oder den Spaltennamen. Wichtig ist dabei, daß der Spaltenindex mit 1 beginnt, d. h., die erste Spalte wird durch 1 bezeichnet, die zweite mit 2 usw. Insgesamt kann das Ergebnis der Anfrage wie folgt ausgewertet werden:

while (rs . next ( ) ) {

String s = rs . getString (1);

double d = rs .getDouble (2);

int i = rs .getInt (3);

System . out .println(s + “ “ + d + “ “ + i );

} Ressourcenfreigabe

Zum Abschluß werden die benutzten Ressourcen durch Aufruf der close-Methoden von ResultSet und Statement freigegeben:

rs .close ( );

stmt .close ( ); Fehlerbehandlung

Fehler werden in JDBC grundsätzlich als Ausnahmen (Exception ) der Klasse SQLException signalisiert und sind daher in geeigneter Weise mit einem try…catch-Block ab-

zufangen und zu behandeln.Details zu einem aufgetretenen

Fehler können über die Methode getMessage ermittelt wer-den, die eine Zeichenkette mit der Beschreibung des Fehlers liefert. Der entsprechende Programmausschnitt zur Fehlerbehandlung ist danach wie folgt zu formulieren:

try {

/ / Aufruf von JDBC-Anweisungen,

/ / die Exception generieren

} catch ( SQLException exc) {

System . out . println ( “ SQLException: “ +

exc . getMessage ( ) );

}

Mit Hilfe der bisher vorgestellten Klassen und Methoden

können wir nun die erste vollständige JDBC-Anwendung erstellen.

Beispiel 1. JDBC-Programm

import java . sql .*;

public class JdbcDemo1 {

public static void main (String [ ] args) {

String driverClass =

“ oracle . jdbc . driver . OracleDriver “;

try { Class . forName ( driverClass );

} catch ( ClassNotFoundException exc ) {

System . out . Println ( exc . getMessage ( ) );

System .exit ( 1 );

}

try {

String url =

“jdbc : oracle : thin:@antarctica:1521:mydb“;

String query = “ SELECT title, price, “ +

“ stock FROM book “;

Connection con =

DriverManager . getConnection ( url , “ tux“ ,

“ pingus “ );

Statement stmt = con .createStatement ( );

ResultSet rs = stmt . executeQuery (query);

while ( rs . next ( ) ) {

String s = rs . getString (1);

double d = rs . getDouble (2);

int i = rs . getInt (3);

System . out . println ( s + “ , “ + d +

“ DM, “ + i );

}

} catch ( SQLException exc ) {

System . out . println (“ SQLException: “

+ exc . getMessage ( ) );

}

}

}

Nachdem wir einen ersten Überblick zur Anwendungsentwic-

klung mit JDBC gewonnen haben, werden wir nun auf

wichtige Aspekte im Detail eingehen.

JDBC im Detail

Verbindungsinformationen

Datenbank: mydb; Server: antarctica ;

Benutzer: tux ; Paßwort: pingus. Treiber und Datenbankverbindung

– TreibermanagerTreibermanager

Der Treibermanager implementiert in der Klasse java .-

sql .DriverManager und bildet die Vermittlungsschicht

zwischen Anwendung und Datenbanktreiber. Da es in

jeder Java-Anwendung nur einen Treibermanager geben

kann, sind alle Methoden statisch. Die Methoden lassen

sich grob in drei Gruppen einteilen:– Registrieren und Laden von Treibern,– Herstellen einer Verbindung zur Datenbank,– Konfigurieren der Verbindung (Protokollierung, Login-

Timeout). Laden von Treibern

-Explizit durch Laden der Treiber

Hierbei wird der JDBC-Treiber über den Aufruf von Class . forName direkt geladen. Einzige Voraussetzung für diese Methode ist ein Java-Klassenpfad, der die

Klassen des benötigten JDBC-Treibers enthält. Da keine weiteren Konfigurationen notwendig sind, ist dies wohl die Methode, die am häufigsten eingesetzt wird.

-Über die Systemeigenschaft sql . Driver

Die Systemeigenschaft ( Property) umfaßt eine Liste von Treibern, die durch Doppelpunkt getrennt sind. Bei der Ini-

tialisierung des Treibermanagers, d. h. beim ersten Aufruf

einer Klassenmethode, werden alle dort angegebenen Trei-ber geladen. Die Eigenschaft kann z. B. beim Aufruf des Java-Interpeters angegeben werden:

java -Djsql . drivers = foo . bar . Driver JdbcDemo1

Eine weitere Möglichkeit sind Property-Files, wie z. B. durch den Browser HOTJAVA oder den Applet-Viewer ausgewertet werden.

In beiden Fällen ist der Name der Klasse der Dokumenta-

tion des Herstellers zu entnehmen. Diese Tabelle zeigt einige wichtige Treiberklassen.

Klassennamen einiger JDBC - Treiber

DBMS Treiberklasse

Oracle 8 oracle . jdbc . driver . OracleDriverDB2 COM . ibm . db2 . jdbc . app .DB2DriverMiniSQL com . Imaginary . sql . msql . MsqlDriverMySQL org .gjt . mm . mysql . DriverODBC sun . jdbc . odbc . JdbcOdbcDriver

TreiberTreiber

Registrierung von TribernRegistrierung von Tribern

Wird ein JDBC-Treiber geladen, so muß dieser sich beim Treibermanager registrieren. Hierzu existieren die Metho-

de

/ / java . sql . DriverManager

static void registerDriver (Driver driver)

throws SQLException;

Die Methode wird normalerweise in einem Initialisierungs-block ( ein static {…. }-Block) der Treiberklasse aufgeru-

fen, der beim Laden der Klasse über Class . forName aus-geführt wird und die Treiberregistrierung vornimmt.

Für die Deregistrierung gibt es eine entsprechende Metho-

de deregisterDriver. Beide Methoden sind aber nur für

Entwickler für Datenbanktreibern interessant.

Weiterhin kann man explizit den Treiber für eine gegebe-

nen JDBC-URL anfordern oder mittels eines Iterators über alle geladenen Treiber navigieren:

/ / java . sql . DriverManager

static Driver getDriver (String url)

throws SQLException;

static java . Util . Enumeration getDrivers ( )

* Iteraor (Enumeration)

Ein für Container-Klassen ( wie Listen, Bäume, Felder, usw. ) sehr nützliches Interface, das eine Möglichkeit bereitstellt, alle Elemente des Containers nacheinander zu

referenzieren.

Das folgende Beispiel zeigt die Typische Anwendung einerEnumeration e:

for (Enumeration e = v . elements ( ) ;

e . hasMoreElements ( ) ; ) {

System . out .println (e . nextElement ( ) ) ;

}

Aufbau einer DatenbankverbindungAufbau einer Datenbankverbindung

VerbindungsaufbauVerbindungsaufbau

Nach dem Laden eines Treibers kann die Verbindung zur

Datenbank aufgebaut werden. Der Treibermanager stellt

hierfür drei verschiedene Methoden bereit, die sich nur in

der Form der Parameterlisten unterscheiden:

/ / java . sql . DriverManager

static Connection getConnection ( String url )

throws SQLException;

static Connection getConnection ( String url ,java . util . Properties info ) throws SQLException;

static Connection getConnection (String url ,String user , String password) throws SQLException;

JDBC-URLJDBC-URL

Alle Methoden erwarten einen Uniform Ressource Locator (URL) als Parameter und liefern ein Connection-Objekt. Die JDBC-URLs sind im Aufbau an die aus dem Web bekannten URLs angelehnt. Sie haben grundsätzlich folgende Form:

jdbc : < subprotocol > : < subname >

Hierbei bezeichnen < subprotocol > den Mechanismus zur Datenbankverbindung (z. B. ein konkretes Protokoll) und < subname > ein Identifikator für die Datenbank. Der <subname >-Teil ist außerdem abhängig vom Protokoll und kann auch eine Netzwerkadresse beinhalten.

Dagegen müssen für eine Verbindung zu einer Oracle-Datenbank die Netzwerkadresse (Hostname und Port) des Datenbankservers bzw. Des Listener-Prozesses sowie der Name der Datenbank angegeben werden :

jdbc : oracle : thin : @antarctica : 1521 : mydb

Beim Aufruf der Methode getConnection versucht der Trei-

bermanager einen Treiber zu finden, der die angegebene

URL akzeptiert. Dazu werden alle geladenen Treiber nach

einander getestet, d. h ., es wird die Methode acceptsURL-

von java . sql .Driver aufgerufen. Mit dem ersten gefunde-nen Treiber wird die Verbindung zur Datenbank herge-

stellt. Als weitere Parameter für den Verbindungsaufbau sind insbesondere Benutzername und Paßwort anzugeben, entweder direkt oder als Schlüssel-Wert-Paare in Form eines Property-Objektes.

Timeouts und ProtokollierungTimeouts und Protokollierung

Timeout :Timeout : Mit den weiteren Methoden der Klasse Driver-Manager kann die maximale Wartezeit für das Anmelden bei der Datenbank (Timeout) abgefragt bzw. geändert wer-

den. Die Zeitangabe erfolgt dabei jeweils in Sekunden:

/ / java . sql . DriverManager

static int getLoginTimeout ( )

static void setLoginTimeout (int seconds)

Tracing :Tracing : Schließlich kann noch ein Ausgabestrom für die Protokollierung (Tracing) vom Treibermanager sowie den Treibern angegeben werden:

/ / java . sql . DriverManager

static java . io . PrintStream getLogStream ( )

static void setLogStream ( java . io . PrintStream out )

Als Parameter muß hier ein Stream-Objekt eingesetzt wer-den, wie z. B. System . out oder ein Strom auf einer geöff-

neten Datei. Auf diese Weise lassen sich Fehlermeldungen protokollieren. Durch Übergabe von null als Parameter kann die Protokollierung wieder abgeschaltet werden. Diese Methoden sind in JDBC2 durch setLogWriter bzw.

getLogWriter ersetzt, die einen PrintWriter-Strom als Para-meter bzw. Ergebnis verwenden.

ConnectionConnection

Ein Connection-Objekt repräsentiert eine Verbindung zur Datenbank. Eine Applikation kann dabei mehrere Verbin-dungen zu einer oder zu verschiedenen Datenbanken öffnen. Wie bereits beschrieben, wird eine Verbindung durch Aufruf der getConnection-Methode des Treiberma-

nagers erzeugt. Über eine geöffnete Verbindung können

SQL-Anweisungen zur Datenbank gesendet und Transak-

tionsabläufe gesteuert werden.Weiterhin lassen sich Infor-mationen über die Datenbank abfragen.

Katalogzugriff: Katalogzugriff: Der Bereich der Datenbank, auf den über die Verbindung zugegriffen werden soll, kann mit den Methoden getCatalog und setCatalog festgelegt bzw. abgefragt werden:

/ / java . Sql . Connection

void setCatalog (String Catalog) throws SQLException;

String getCatalog ( ) throws SQLException;

Jedes Datenbankobjekt (Relationen, Sichten, Prozeduren, usw.) ist eindeutig über das Tripel (Katalogname, Schema-

name, Objektname) identifizierbar, wobei im Normalfall der Katalogname dem Datenbanknamen und der Schema-name dem Benutzernamen entspricht. Für eine Verbindung ist der Katalog auf den Default-Katalog des angemeldeten Benutzers initialisiert, so daß diese Methoden nur selten benötigt werden. Die exakte Bedeutung des Katalogna-

mens ist jedoch vom DBMS abhängig.

Mit der Methode setReadOnly kann angegeben werden, daß nachfolgend nur Leseoperationen ausgeführt werden

sollen.

/ / java . sql . Connection

void setReadOnly ( boolean readOnly )

throws SQLException;

boolean isReadOnly ( ) throws SQLException;

Allerdings bedeutet das nicht, daß Schreiboperationen damit verboten sind. Vielmehr ist es ein Hinweis für den Treiber und das DBMS und z. B. Optimierungen vorzuneh

men. Der aktuelle Modus der Verbindung kann über isReadOnly abgefragt werden. Für einen Treiber, der keine Schreibinformationen unterstützt, wird hier entsprechend auch true zurückgegeben.

Verbindungsabbau:Verbindungsabbau: Eine aktive Verbindung zur Daten-

bank wird mittels der close-Methode beendet.

/ / java . sql . Connection

void close ( ) throws SQLException;

boolean isClosed ( ) throws SQLException;

Obwohl das Schließen auch automatisch bei der Freigabe des Objektes durch den Garbage Collector erfolgt, ist das explizite Schließen die empfohlene Variante. So können Ressourcen des DBMS sofort freigegeben werden, wenn sie nicht mehr benötigt werden. Das automatische Schlie-

ßen wird dagegen unter Umständen (z. B. Hauptspeicher) erst viel später erfolgen. Der Zustand einer Verbindung ist wiederrum über die Methode isClosed abgefragbar.

TransaktionssteuerungTransaktionssteuerung

Der Begriff der Transaktion ist als elementare Ausführungs-

einheit zur Überführung der Datenbank von einem konsis-

tenten Zustand in einen veränderten, konsistenten Zustand

unter Einhaltung des ACID-Prinzips vorgestellt. Unter

ACID versteht man:

Atomarität = Ununterbrechbarkeit.

Konsistenz = Integritätserhaltung.

Isolation = Isolation.

Dauerhaftigkeit = Persistenz der Ergebnisse.

Die Kommandos zur Steuerung des Transaktionsablaufes

sind als Methoden der Schnittstelle Connection definiert:

/ / java . Sql . Connection

void commit ( ) throws SQLException;

void rollback ( ) throws SQLException;

Mit der Methode commit wird angezeigt, daß die Tran-

saktion erfolgreich abgeschlossen werden soll und alle Än

derungen permanen t in die Datenbank zu schreiben sind.

Mit rollback wird die aktive Transaktion abgebrochen -

alle Änderungen, die im Rahmen dieser Transaktion durch-geführt wurden, werden rückgängig gemacht.Ein explizites >> Begin of Transaction << existiert dagegen nicht. Tran-saktionen werden - wie in relationalen Datenbanksystemen üblich - automatisch mit dem ersten Datendefinitions- bzw. Datenmanipulationsbefehl bzw. mit dem Ende oder Ab-

bruch der vorangegangenen Transaktion gestartet.

Auto-Commit: Auto-Commit: Wird eine neue Verbindung zur Datenbank hergestellt, so befindet sich diese im Auto-Commit-Modus, d. h., nach jeder Anweisung wird automatisch ein Commit ausgeführt und eine Transaktion umfaßt jeweils nur eine Anweisung. Dieser Modus kann mit der Methode

setAutoCommit ein- (mit true als Parameter) bzw.

ausgeschaltet (false) werden:

/ / java . Sql . Connection

void setAutoCommit (boolean enable)

throws SQLException;

boolean getAutoCommit ( ) throws SQLException;

Ohne Auto-Commit wird die Transaktion erst mit einem expliziten Commit bzw. Rollback abgeschlossen. Durch

das Aabschalten des Auto-Commit-Modus lassen sich meh

-rere Anweisungen zu einer Transaktion zusammenfassen. Außerdem können so Änderungen bis zum Ende der Tran-

saktion rückgängig gemacht werden. Das folgende Beispiel zeigt die Nutzung von Transaktionen beim Einfügen meh-

rerer Datensätze, wobei beim Auftreten eines Fehlers alle Änderungen zurückgenommen werden.

Die Fehlermeldung wird außerdem durch Weiterleiten der Ausnahme an den Aufrufer propagiert:

try {

stmt = con . createStatement ( );

con .setAutoCommit ( false) ;

stmt . executeUpdate ( “ INSERT INTO book “ + “ VALUES ( ‘ 3-608--93421-9 ‘ , ‘ Otherland ‘ , “ +

“ 2, 1, 49.90, 20 ) “ );

stmt . executeUpdate ( “ INSERT INTO author “ + “ VALUES (1, ‘Tad‘ , ‘Williams‘ )“ );

stmt . executeUpdate ( “ INSERT INTO book_author “ + “ VALUES (‘3- 608-93421-9‘ ,

1)“);

con . Commit ( );

} catch (SQLException exc) { con . Rollback ( );

throws exc;

}

Für eine Reihe von Anwendungen ist die strenge Einhaltung

der ACID-Eigenschaften jedoch zu restriktiv und zu Lauf-

zeiteinbußen.

Ausführung von SQL-Anfrage

In JDBC wird jede SQL-Anweisung durch ein Statement-Objekt gekapselt. Dieses Objekt sendet die Anweisung zur Datenbank, liefert das Ergebnis zurück und verarbeitet

Parameter, die der Anweisung übergeben werden. Es wer-

den drei Formen von Statements unterstützt:

Arten von Statements:Arten von Statements:

java . sql .Statement als Basisschnittstelle für alle anderen Formen erlaubt die Verarbeitung einfacher Anweisungen ohne Parameter.

Java . sql .PreparedStatement kapselt eine vorkompilierte Anweisung und wird insbesondere dann eingesetzt, wenn eine Anweisung mehrfach und mit verschiedenen IN-Para-

metern ausgeführt werden soll.

Java . sql .CallableStatement ermöglicht den Aufruf von gespeicherten Prozeduren mit IN- und OUT-Parametern.

Erzeugen von AnweisungenErzeugen von Anweisungen

- - Erzeugen von StatementsErzeugen von Statements

Ein Statement-Objekt wird grundsätzlich über die Connec-

tion-Schnittstelle erzeugt. Hierzu ist für jede Anweisungs-

form eine eigene Methode definiert:

/ / java . sql . Connection

Statement createStatement ( ) throws SQLException;

PreparedStatement preparedStatement (String sql)

throws SQLException;

CallableStatement prepareCall ( String sql)

throws SQLException;

Ausführung von AnweisungenAusführung von Anweisungen

Die Statement- Schnittstelle definiert als Basisschnittstelle die Methoden für alle Anweisungsformen. Zur Ausführung der Anweisungen stehen drei execute-Methoden zur Verfü-

gung.

/ / java . sql . Statement

ResultSet executeQuery ( String sql)

throws SQLException;

int executeUpdate (String sql) throws SQLException;

boolean execute (String sql) throws SQLException;

-Ausführung von SELECT-AnweisungenAusführung von SELECT-Anweisungen

Mit der Methode executeQuery wird eine SELECT-Anwei-

sung ausgeführt. Diese Methode liefert ein ResultSet-Ob-

jekt mit dem Anfrageergebnis:

Statement stmt = con . createStatement ( );

ResultSet rs = stmt . executeQuery (“ SELECT * FROM book“);

Ausführung von DDL- und DML-AnweisungenAusführung von DDL- und DML-Anweisungen

DDL-(Database Definition Language) und DML-(Database Manager Language) Anweisungen, d. h. CREATE TABLE oder INSERT, UPDATE und DELETE, werden über die

Methode executeUpdate zur Datenbank gesendet. DML-Anweisungen manipulieren Tupel einer Relation, das Er-

gebnis ist demnach die Anzahl der betroffenen Tupel. Für DDL-Anweisungen ist dagegen der Rückgabewert immer 0.

Int nrows = stmt . executeUpdate (“ DELETE FROM customer WHERE cust_id = 256 “);

Anweisungen mit mehreren ErgebnisseAnweisungen mit mehreren Ergebnisse

Eine besondere Behandlung erfordert Anweisungen, die

mehrere Ergebnisse liefern. Dies kann z.B. bei gespeicher-

ten Prozeduren auftreten, die mehrere UPDATE-Operatio-

nen oder mehrere Anfragen ausführen. Für diese (eher selte

nen) Fälle wird die Methode execute verwendet. Diese Me-

thode liefert den Wert true, wenn das Ergebnis der Anfrage

ein ResultSet-Objekt ist ( z. B. nach einem SELECT ) und false, wenn es ein Integer-Wert ist (z. B. die Anzahl der

betroffenen Tupel nach einem UPDATE). Das entsprechen-

de Ergebnis wird mit den folgenden Methoden ermittelt:

/ / java . sql .Statement

ResultSet getResultSet ( ) throws SQLException;

int getUpdateCount ( ) throws SQLException;

boolean getMoreResults ( ) throws SQLException;

Ein ResultSet-Objekt wird danach durch getResultSet gelie-fert, die Anzahl der betroffenen Tupel mit getUpdateCount Ob weitere vorliegen und von welcher Art diese sind, kann mit getMoreResults erfragt werden. Diese Methode liefert true, wenn das nächste Ergebnis ein ResultSet-Objekt ist, und false für einen Integer-Wert. Das jeweils nächste Ergebnis wird durch getResultSet bzw. geUpdateCount ermittelt, wobei getResultSet den Wert null zurückgibt, wenn das Ergebnis ein Integer-Wert ist und getUpdate-Count einen der folgenden Werte liefert:

>0 für eine UPDATE-, INSERT- oder DELETE-Operation

0 für eine DDL-Operation bzw. eine DML-Operation, die keine Tupel verändert hat, und

-1, wenn das Ergebnis ein ResultSet-Objekt ist oder keine weiteren Ergebnisse vorliegen.

Damit sind alle Ergebnisse ermittelt, wenn die Bedingung gilt: (getMoreResults ( ) = = false) & &

(getUpdateCount ( ) = = -1)

Das folgende Beispiel demonstriet die verwendung dieser Methoden beim Aufruf einer gespeicherten Prozedur, die mehrere ResultSets zurüchgeben kann.:

CallableStatement stmt = con. prepareCall (“

{ call MultipleResultsProc } “); stmt. execute ( ) ;

while (stmt. getMoreResults ( ) )

{ResultSet rs = stmt. getResultSet ( );

/ / ResultSet auswerten

}

Parameter für Ausführung von AnweisungenParameter für Ausführung von Anweisungen

Weiterhin lassen sich die Ausführung von Anweisungen sowie die Ergebnisgröße beeinflussen. Mit setQueryTime-

out wird die maximale Zeit des Wartens auf die Ausfüh-

rung in Sekunden festgelegt, wobei der Default-Wert von 0 für unbegrenztes Warten steht. Ein Überschreiten des gesetzten Limits wird durch eine Exception signalisiert. Die Maximale Anzahl von Tupeln im Anfrageergebnis wird mit der Methode setMaxRows vordefiniert. Auch hier ist der Default-Wert 0 und bedeutet keine Einschränkung der Anzahl. Wird dagegen ein anderer Wert angegeben, so werden nur die entsprechende Anzahl von Tupeln ausgele-

sen, der Rest wird ignoriert. Die Maximale Größe einer Spalte in Bytes kann mit setMaxFieldSize festgelegt wer-

den, wobei dies nur für die SQL-Typen VARBINARY,

LONGVARBINARY, CHAR, VARCHAR und LONGVAR-

CHAR relevant ist. Überschreiten die Daten das festgelegte

Limit, so wird der Rest abgeschnitten. Der Default-Wert

von 0 bedeutet auch hier keine Beschränkung.

/ / java . sql . Statement

int getMaxFieldSize ( ) throws SQLException;

void setMaxFieldSize (int max) throws SQLException;

int getMaxRows ( ) throws SQLException;

void setMaxRows (int max) throws SQLException;

int getQueryTimeout ( ) throws SQLException;

void getQueryTimeout (int secs ) throws SQLException;

Abbruch von TransaktionenAbbruch von Transaktionen

Schließlich läßt sich die Ausführung einer Anweisung über

die Methode cancel durch einen anderen Thread (Ausfüh

rungsfaden)abbrechen, wenn Treiber und DBMS dies unter-

stützen.

/ / java . sql . Statement

void cancel ( ) throws SQLException;

void close ( ) throws SQLException;

Nachdem eine Anweisung ausgeführt und die Ergebnisse

ermittelt wurden, sollten damit verbundene Ressourcen

durch Aufruf der close-Methode freigegeben werden. Auch

hier gilt die bereits beim Connection-Objekt gegebene Emp

-fehlung der expliziten Freigabe gegenüber dem automa-

tischen Schließen durch den Garbage Collector („ Speicher-

freigeber “).

Abbildung von SQL-Typen in javaAbbildung von SQL-Typen in java

Da SQL und Java jeweils eigene Typsysteme besitzen, muß

eine Abbildung zwischen beiden definiert werden. Das Pro

-blem der Typabbildung tritt in JDBC an drei Stellen auf:

beim Zugriff auf Spaltenwerte eines Tupels mit den getXXX-Methoden der Schnittstelle ResultSet,

bei der Übergabe von Parametern an ein PreparedState

-ment mit den setXXX-Methoden sowie

beim Zugriff auf die OUT-Parameter eines CallableSta-

tements.

SQL - Typbezeichner:SQL - Typbezeichner: Darüber hinaus existiert noch eine weitere Schwierigkeiten: Einige SQL-Typen werden von den DBMS-Herstellern teilweise unterschiedlich bezeich-

net, insbesondere die Datentypen zum Speichern großer

Binärdaten. Zur Überwindung dieser Inkompatibilitäten sind in JDBC zunächst einige generische Typbezeichner definiert. Diese sind in der Klasse java . sql . Types als Konstanten zusammengefaßt:

CHAR, VARCHAR, LONGVARCHAR für Zeichenketten

BIT für Bitwerte und BINARY,VARBINARY, LONGVAR

-BINARY für Binärfelder,

TINYINT, SMALLINT, BIGINT und INTEGER für In-teger-Werte,

REAL, FLOAT und DOUBLE für Gleitkommawerte,

DATE, TIME, TIMESTAMP für Datums- und Zeitwerte.

Diese Konstanten werden in JDBC überall dort verwendet,

wo SQL-Typen anzugeben sind, also z. B. beim Registrie-

ren von OUT-Parametern für gespeicherte Prozeduren. Die

Umsetzung in die DBMS-spezifischen Typen erfolgt - wenn notwendig - durch den Treiber.

Beim Auslesen von Werten aus einem ResultSet-Objekt bzw. bei der Übergabe von IN-Parametern an ein Prepared

-Statement sind dagegen die getXXX- bzw. setXXX-Metho-

den zu verwenden. Hierbei findet ebenfalls eine Konvertie-

rung zwischen SQL- und Java-Typ durch den Treiber statt. Die verwendete Abbildungsvorschrift ist in nachfolgenden Tabelle dargestellt. Die getXXX- und setXXX-Methoden sind entsprechend dem Java-Typ bezeichnet, wobei für die Byte-Felder getBytes bzw. setBytes verwendet wird. Der in der Tabelle angegebene Java-Typ ist auch der Typ, der beim Aufruf von getObject zurückgegeben wird.

Datums- und Zeittypen:Datums- und Zeittypen:

Zur Repräsentation der Datums- und Zeittypen sind in

JDBC drei zusätzliche Klassen definiert: Date, Time und

Timestamp. Diese Klassen kapseln im wesentlichen die Funktionalität der Klassen aus java . util und fügen nur noch die Behandlund der Escape-Syntax hinzu. So kann ein Date-Objekt für den 18. Februar 1999 über den nor- malen Konstruktoraufruf erzeugt werden:

Date d = new Date ( 99 , 2 , 18 );

Das erste Argument bezeichnet dabei die Jahreszahl minus 1900, d. h., für das Jahr 2000 ist dementsprechend der Wert 100 anzugeben. Das zweite und dritte Argument sind Monat und Tag. Alternativ dazu kann das Date-Objekt auch durch Aufruf der statischen Methode valueOf erzeugt werden:

Date d = Date . valueOf ( “ 1999 - 02 - 18 “ );

Diese Methode ist eine Zeichenkette mit dem gewünschten

Datum in Escape-Syntax als Argument zu übergeben. In

Ähnlicher Weise wird die Klasse java . sql .Time zur Reprä-

sentation der Uhrzeit (SQL-Typ Time) verwendet. Hier ist

das Format der Zeitangabe hh : mm : ss.

Tabelle : Abbildung zwischen Java- und JDBC-Typen Abbildung zwischen Java- und JDBC-Typen .

JDBC -Typ Java-Typ

CHARVARCHARLONGVARCHARNUMERICDECIMALBITTINYINTSMALLINT

StringStringStringjava . math . BigDecimaljava . math . BigDecimal booleanbyteshort

INTEGERBIGINTREALFLOATDOUBLEBINARYVARBINARYLONGVARBINARYDATETIMETIMESTAMP

intlongfloatdoubledoublebyte [ ]byte [ ]byte [ ]java . sql . Datejava . sql . Timejava . sql . Timestamp

BEISPIELANWENDUNG MIT JDBC

Beispiel 1: Eintragen einer Bestellung

Die Methode createOrder zum Anlegen einer Bestellung ist etwas aufwendiger. Hier ist zunächst die Bestellung als ein Tupel in die Relation book_order einzutragen und für jeden Artikel dieser Bestellung zusätzlich noch ein Tupel in die Relation order_item einzufügen. Die einzelnen Artikel werden dabei durch Einlesen der ISBN sowie der Anzahl vom Benutzer erfragt. Da die Ausführung der ein-

zelnen Anweisungen aufgrund von Verletzungen der Inte-

gritätsbedingungen (z. B. wenn ISBN oder Kundennummer nicht existieren) fehlschlagen kann, muß der gesamte Ab-

lauf als eine Transaktion realisiert werden. Hierzu wird das Auto-Commit zu Beginn ausgeschaltet und im Fehlerfall ein Rollback ausgeführt. Erst wenn die Bestellung voll-

ständig erstellt werden konnte, wird das abschließende Commit gesendet.

Programm:

void createOrder (int custId)

throws SQLException {

boolean ready = false;

preparedStatement stmt1, stmt2;

try {

con . setAutoCommit (false);

/ / Bestellung Eintragen

stmt1 = con . prepareStatement (

“ INSERT INTO book_order “ +

“ VALUES ( order_seq. NEXTVAL, ?, “ + “ SYSDATE, 0 ) “);

stmt1 . setInt (1, custId);

stmt1 . executeUpdate ( );

stmt2 = con . prepareStatement (

“ INSERT INTO order_item “ +

“ VALUES (order_seq . CURRVAL, ?, ?)“ );

do{

/ / ISBN erfragen

String isbn = Utils . readString ( “ isbn: “);

if ( isbn = = null | | isbn . Length ( ) = = 0 )

ready = true;

else {

/ / Anzahl erfragen

int num = Utils . readInt ( “ number: “ );

if (num > 0) {

/ / Bestellposition eintragen

stmt2 . setString ( 1, isbn );

stmt2 . setInt ( 2, num);

stmt2 . ExecuteUpdate ( );

}

}

} while (! ready);

con . commit ( );

}

catch ( SQLException exc ) {

con . Rollback ( ); throws exc;}

}