Datenbankanbindung: JDBC und SQLJ



Ähnliche Dokumente
SQLJ. Standardisierte Java-DB. DB-Schnittstelle. Spezifikationen. Oracle, IBM, Informix, Sybase,, Tandem, Sun, Microsoft stehen dahinter

seit Java 1.1 Bestandteil der API: packages java.sql, javax.sql

Java Database Connectivity (JDBC) Walther Rathenau Gewerbeschule 1

Universität Stuttgart Abteilung Anwendersoftware Steht für Embedded SQL in Java. - Java-Methoden als SQL Stored-Procedures

JDBC. Es kann z.b. eine ODBC-Treiberverbindung eingerichtet werden, damit das JAVA-Programm auf eine ACCESS-DB zugreifen kann.

Oracle: Abstrakte Datentypen:

Dynamisches SQL. Folien zum Datenbankpraktikum Wintersemester 2009/10 LMU München

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen.

Java: Vererbung. Teil 3: super()

Datenbankentwurf & Datenbankzugriff mit JDBC. Georg Köster Sven Wagner-Boysen

3. Stored Procedures und PL/SQL

Gesicherte Prozeduren

Datenbanken & Informationssysteme Übungen Teil 1

2. Datenbank-Programmierung

Inhalt. 1 Einleitung AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER

Kapitel 10. JDBC und SQLJ. Prof. Dr. Wolfgang Weber Vorlesung Datenbanken 1

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Java Kurs für Anfänger Einheit 5 Methoden

Einrichtung des Cisco VPN Clients (IPSEC) in Windows7

Autorisierung. Sicherheit und Zugriffskontrolle & Erstellen einer Berechtigungskomponente

Programmieren in Java

Beispiel: DB-Mock (1/7)

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

Anleitung IPSec VPN. Datum: Version: 1.1. Gültig ab: Ablage:

Datenbank und Informationssysteme

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

JDBC. Allgemeines ODBC. java.sql. Beispiele

Objektorientierte Programmierung

Reporting Services und SharePoint 2010 Teil 1

Objektorientierte Programmierung. Kapitel 12: Interfaces

Informatik 12 Datenbanken SQL-Einführung

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

Updatehinweise für die Version forma 5.5.5

SEMINAR Modifikation für die Nutzung des Community Builders

5.2 Neue Projekte erstellen

Upgrade auf die Standalone Editionen von Acronis Backup & Recovery 10. Technische Informationen (White Paper)

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Programmierkurs Java

Testen mit JUnit. Motivation

Fachbericht zum Thema: Anforderungen an ein Datenbanksystem

2 Die Terminaldienste Prüfungsanforderungen von Microsoft: Lernziele:

Einführung in Java. PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005

Über die Internetseite Hier werden unter Download/aktuelle Versionen die verschiedenen Module als zip-dateien bereitgestellt.

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster

Prinzipien Objektorientierter Programmierung

Folgendes PL/SQL Codefragment zeigt das grundlegende Statement für diesen Test: Java.

Database Exchange Manager. Infinqa IT Solutions GmbH, Berlin Stralauer Allee Berlin Tel.:+49(0) Fax.:+49(0)

OP-LOG

php Hier soll ein Überblick über das Erstellen von php Programmen gegeben werden. Inhaltsverzeichnis 1.Überblick Parameterübergabe...

Wie richten Sie Ihr Web Paket bei Netpage24 ein

Öffnen Sie den Internet-Browser Ihrer Wahl. Unabhängig von der eingestellten Startseite erscheint die folgende Seite in Ihrem Browserfenster:

DATENBANKEN SQL UND SQLITE VON MELANIE SCHLIEBENER

Grundlagen von Python

SEP 114. Design by Contract

Handbuch ECDL 2003 Basic Modul 5: Datenbank Grundlagen von relationalen Datenbanken

Pakete dienen dazu, die Software eines Projektes in größere inhaltlich zusammengehörige Bereiche mit eigenem Namen einzuteilen (siehe Java API).

- Zweimal Wöchentlich - Windows Update ausführen - Live Update im Norton Antivirusprogramm ausführen

pro4controlling - Whitepaper [DEU] Whitepaper zur CfMD-Lösung pro4controlling Seite 1 von 9

Web-Kürzel. Krishna Tateneni Yves Arrouye Deutsche Übersetzung: Stefan Winter

Berechtigungen im Kalender Anleitung für die Rechtevergabe im Outlook Kalender FHNW, Services, ICT

Übung: Verwendung von Java-Threads

Einführung in die Programmierung

Tapps mit XP-Mode unter Windows 7 64 bit (V2.0)

Bauteilattribute als Sachdaten anzeigen

Applet Firewall und Freigabe der Objekte

Bedienungsanleitung. Matthias Haasler. Version 0.4. für die Arbeit mit der Gemeinde-Homepage der Paulus-Kirchengemeinde Tempelhof

Fachdidaktik der Informatik Jörg Depner, Kathrin Gaißer

TeamSpeak3 Einrichten

Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress.

Vorkurs C++ Programmierung

Installation der SAS Foundation Software auf Windows

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden.

Kurzanleitung zur Bereitstellung von Sachverhalten und Lösungen zum Universitätsrepetitorium auf dem Server unirep.rewi.hu-berlin.

Um zu prüfen welche Version auf dem betroffenen Client enthalten ist, gehen Sie bitte wie folgt vor:

Version NotarNet Bürokommunikation. Bedienungsanleitung für den ZCS-Import-Assistenten für Outlook

2. Einrichtung der ODBC-Schnittstelle aus orgamax (für 32-bit-Anwendungen)

Registrierung am Elterninformationssysytem: ClaXss Infoline

Unsere Webapplikation erweitern

Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0)

PHPNuke Quick & Dirty

Installation von NetBeans inkl. Glassfish Anwendungs-Server

YouTube: Video-Untertitel übersetzen

Suche schlecht beschriftete Bilder mit Eigenen Abfragen

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

4. BEZIEHUNGEN ZWISCHEN TABELLEN

Nach der Anmeldung im Backend Bereich landen Sie im Kontrollzentrum, welches so aussieht:

Handbuch Fischertechnik-Einzelteiltabelle V3.7.3

ICS-Addin. Benutzerhandbuch. Version: 1.0

Lizenzen auschecken. Was ist zu tun?

IBM SPSS Data Access Pack Installationsanweisung für Windows

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Artikel Schnittstelle über CSV

Datenbanksysteme SS 2007

ID VisitControl. Dokumentation Administration Equitania Software GmbH cmc Gruppe Seite 1

Einführung in die Java- Programmierung

Transkript:

Prof. Dr. Klaus Dittrich Datenbankanbindung: JDBC und SQLJ Betreuung: Anca Dobre Jussi Prevost Borrweg 60 8055 Zürich jprevost@access.unizh.ch

Inhaltsverzeichnis 1. Einleitung... 3 2. Grundlagen... 3 2.1. Einsatzfälle...3 2.2. Die Architektur von JDBC...4 A. Treiber...4 B. Programmierkonzept...5 2.3. SQLJ...8 A. Zweck...9 B. Überblick...9 C. Hostausdrücke...10 D. In or Out?...11 E. Iteratoren...11 3. Vergleich... 12 3.1. Verbindungsaufbau...14 3.2. Insert...14 3.3. Select...14 3.4. Online-Überprüfung...14 3.5. Geschwindigkeit...15 4. Zusammenfassung... 15 Literaturverzeichnis... 16 2

1. Einleitung JDBC (Java DataBase Connectivity) 1 ist eine herstellerneutrale Programmierschnittstelle (Application programming interface, API). Sie erlaubt den Programmierern, Verbindung zu einer Datenbank herzustellen und mittels SQL die Datenbank abzufragen oder zu aktualisieren, ohne sich um die spezifischen Eigenheiten eines bestimmten Datenbanksystems zu kümmern. Um die Unterschiede kümmern sich sogenannte JDBC-Treiber, welche von den jeweiligen Datenbankherstellern bereitgestellt werden. Die JDBC-API ist vollständig in Java implementiert und ist somit auch plattformunabhängig. SQLJ befasst sich mit verschiedenen Aspekten der Integration von SQL und Java. SQLJ besteht aus drei Teilen: Der erste Teil (SQLJ Teil 0) stellt eine standardisierte Syntax und Semantik für die Einbettung von SQL in Java-Programmen zur Verfügung. Dabei bietet er gegenüber dem JDBC-Kit eine einfachere Verwendung und Überprüfungsmöglichkeiten der SQL Abfragen schon zu Übersetzungszeit. Der zweite Teil (SQLJ Teil 1) befasst sich mit der Implementierung von Prozeduren und Funktionen in Java, welche in einer Datenbank gespeichert werden können. Der dritte Teil (SQLJ Teil 2) beschreibt Möglichkeiten, wie man Java-Datentypen und -Klassen als benutzerdefinierte SQL-Datentypen in einer Datenbank ablegen kann. In dieser Arbeit werde ich mich auf JDBC und SQLJ Teil 0 2 konzentrieren, weil es um einen Überblick von Datenbankanbindung in Java geht. Wer sich für weitere Details von SQLJ Teil 1 und 2 interessiert, findet im Literaturverzeichnis weiterführende Referenzen. 2. Grundlagen 2.1. Einsatzfälle Wer eine Anwendung oder ein Applet in Java realisiert und dabei eine Datenbankanbindung benötigt, braucht JDBC oder SQLJ. Anwendungen haben dabei vollkommen freie Hand, um auf (verteilte) Datenbankserver zuzugreifen. Applets können nur eine Datenbankverbindung zu dem Server öffnen, von dem sie der Benutzer heruntergeladen hat. Das heisst Datenbankund Webserver müssen sich auf demselben Computer befinden, was kein typisches Setup ist. Für signierte Applets sind diese Restriktionen gelockert. Für die Realisierung der Anwendung spielt es keine Rolle, ob eine herkömmliche Client- /Server-Architektur oder eine Multi-Tier-Architektur verwendet wird. 1 JDBC ist ein geschützter Markenname und eigentlich keine Abkürzung. Trotzdem wird JDBC vielfach als eine Abkürzung für Java Database Connectivity betrachtet. 2 Ich verwende ab jetzt nur noch die Bezeichnung SQLJ. 3

2.2. Die Architektur von JDBC JDBC besteht aus zwei Schichten. Die obere Schicht ist die eigentliche JDBC API. Diese kommuniziert mit der unteren Schicht, dem JDBC-Treibermanager-API, und sendet dieser die verschiedenen SQL-Anweisungen. Der Treibermanager sollte mit den verschiedenen Treibern von Drittherstellern kommunizieren, welche die eigentliche Verbindung zur Datenbank herstellen. Der Programmierer muss sich nicht um herstellerspezifische Eigenheiten von DBMS kümmern. Diese Unterschiede übernimmt ein JDBC-Treiber vom jeweiligen Datenbankhersteller. Abbildung 1 gibt einen Überblick. Abbildung 1: Die Architektur von JDBC A. Treiber Wie aus Abbildung 1 ersichtlich ist, werden vier verschiedene Typen von Treibern unterschieden, die zumindest den SQL-92 Entry Level unterstützen müssen. 1. Ein Typ 1 Treiber (JDBC-ODBC Brücke) benützt die ODBC 3 -Schnittstelle, um mit der Datenbank zu kommunizieren. Ein solcher Treiber wird im JDK angeboten. Allerdings muss auf allen Clients eine ODBC-Schnittstelle installiert sein, was nicht immer ist bzw. möglich wäre. 2. Ein Typ 2 Treiber (Native API Treiber) ist zum Teil in Java geschrieben, benutzt aber bestimmte Schnittstellen von DBMS. Für eine Installation wird nicht nur die 3 Open Database Connectivity; DB-Zugriffsschnittstelle von Microsoft 4

Java-Bibliothek benötigt, sondern auch Bibliotheken vom jeweiligen Datenbankhersteller. 3. Ein Typ 3 Treiber (JDBC-Net Treiber) ist eine reine Client-Bibliothek in Java, die über ein datenbankunabhängiges Protokoll Datenbankanforderungen an eine Serverkomponente schickt, die wiederum die Anforderungen in ein datenbankspezifisches Protokoll umsetzt. Die Client-Bibliothek ist unabhängig von der eigentlichen Datenbank und vereinfacht somit die Entwicklung. 4. Ein Typ 4 Treiber (Native-Protokoll Treiber) ist auch eine reine Java-Bibliothek, die JDBC-Anforderungen direkt in ein datenbankspezifisches Protokoll übersetzt. Die meisten Datenbankhersteller stellen ihren Datenbanken entweder einen Typ 3 oder Typ 4 Treiber zur Verfügung. Typ 1 und Typ 2 Treiber werden oft für das Testen verwendet oder in Unternehmensnetzwerken, wo die zusätzliche Installation der notwendigen Bibliotheken kein grosses Problem sein sollte. B. Programmierkonzept Die für die JDBC-Programmierung verwendeten Klassen sind im Paket java.sql enthalten. Abbildung 2 zeigt die wichtigsten Klassen. Abbildung 2: Die wichtigsten Klassen in JDBC Bei der Programmierung geht man nach folgenden Schritten vor: 1. Verbindung zur Datenbank herstellen (über den JDBC-Treiber) 2. SQL-Anweisung an ein sogenanntes Statement-Objekte übergeben 3. Statement ausführen 4. evt. Abfrageergebnis verarbeiten 5. nicht mehr verwendete Objekte freigeben Auf diese fünf Punkte werde ich jetzt kurz eingehen. In Kapitel 3 folgt dann ein zusammenhängendes Beispiel. 5

1) Verbindung herstellen Über die Klasse DriverManager wählt man einen Datenbanktreiber aus und erstellt eine neue Datenbankverbindung. Der Treibermanager muss einen Treiber allerdings erst registrieren, bevor er ihn aktivieren kann. Das folgende Beispiel registriert die JDBC-ODBC-Brücke von Sun: Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); Jetzt kann die Verbindung zur Datenbank hergestellt werden. Die Verbindung wird dabei als Objekt vom Typ Connection repräsentiert. Zum Verbindungsaufbau werden drei Parameter benötigt. Der erste Parameter ist eine URL 4, welche den Verbindungsmechanismus, den Treiber und den Namen der Datenbank beinhaltet. Die beiden anderen Parameter sind Benutzername und Passwort. String url = "jdbc.odbc.seminardb"; String username = Jussi ; String pw = "seminar"; Connection con = DriverManager.getConnection(url, username, pw); Die Verbindung zur Datenbank steht nun. 2) SQL-Anweisungen SQL-Anweisungen werden als Statement-Objekte behandelt. Diese Objekte senden Anweisungen zur Datenbank und empfangen die zurückgelieferten Ergebnisse. Dabei werden drei verschiedene Arten von Statements unterschieden: 1. java.sql.statement ist die Basisklasse für die Verarbeitung von Anweisungen. Ein Statement-Objekt kann dabei für mehrere Abfragen und Anweisungen benutzt werden (z.b. innerhalb einer Transaktion). 2. java.sql.preparedstatement ist eine Klasse, welche die Verarbeitung von vorbereiteten Anweisungen zulässt. Dabei wird ein sogenannter IN-Parameter (vgl. zu IN und OUT Seite 11) in der SQL-Anweisung durch eine Hostvariable ersetzt. Als Platzhalter dient ein?. Bevor man nun die vorbereitete Anweisung ausführt, muss man die Hostvariable mit der passenden set-methode an den tatsächlichen Wert binden. Es gibt für jeden Datentyp eine set-methode. 3. java.sql.callablestatement ist eine Klasse, welche die Verarbeitung von gespeicherten Prozeduren ermöglicht. Darauf gehe ich nicht weiter ein. 3) Ausführen von Anweisungen Zum Ausführen der Anweisungen benötigt man noch zusätzliche Methoden. Dabei muss man zwischen Abfragen (SELECT) und anderen Anweisungen (Datendefinition und Datenmanipulation) unterscheiden. 6

Für Abfragen dient executequery(string sql) Im Erfolgsfalle wird das Ergebnis in einem java.sql.resultset zurückgeliefert. Die Ergebnismenge kann dabei durch den Aufruf von next() zeilenweise durchlaufen werden. Statement stmt = con.createstatement(); String query = "SELECT Nachname, Gehalt FROM Angestellter " + "WHERE Gehalt > 5000"; ResultSet rs = stmt.executequery(query); while (rs.next()) System.out.println("Name: " + rs.getstring(1) + " " + "Gehalt: " + rs.getdouble("gehalt")); rs.close(); Für Datendefinitionen und Datenmanipulationen muss hingegen executeupdate(string command) verwendet werden. Diese Methode liefert im Erfolgsfall die Anzahl veränderter Zeilen zurück, die von der SQL-Anweisung betroffen waren. Statement stmt = con.createstatement(); String cmd = "UPDATE Angestellte SET Gehalt = Gehalt * 1.1" + "WHERE Nachname = 'Prevost'"; stmt.executeupdate(cmd); Daneben gibt es noch eine allgemeine Methode execute, mit der sich beliebige SQL- Anweisung ausführen lassen. Die Methode liefert true, wenn das Ergebnis ein ResultSet ist, und false, wenn es ein Integer-Wert ist. 4) Ergebnisse von Abfragen Wie wir gesehen haben, werden Abfrageergebnisse in einem java.sql.resultset dargestellt. Ein ResultSet verwaltet einen internen Zeiger, der einen tupelweisen Zugriff auf die Ergebnismenge erlaubt (Ähnlich dem java.util.iterator). Der Zeiger ist dabei zu Beginn auf eine Position vor der ersten Zeile gesetzt. Folglich muss man die Methode next 5 einmal aufrufen, um den Iterator auf die erste Zeile zu setzen. Dies wird normalerweise in einer while-schleife gemacht: while (rs.next()) { Zeile der Ergebnismenge betrachten } Für den Zugriff auf den Inhalt einer Spalte gibt es verschiedene Zugriffsmethoden. Für jeden Java-Typ gibt es Zugriffsmethoden wie getstring und getdouble. Jede Zugriffsmethode hat zwei Formen, eine mit einem numerischen Parameter und eine mit einer Zeichenfolge. Übergibt man ein numerisches Argument, bezieht man sich auf die Spalte mit dieser Nummer (z.b. rs.getstring(1);). Zu beachten ist, dass die Nummerierung der Datenbankspalten 4 Uniform Resource Locator 5 Im JDBC 2 wurden auch andere Navigationsmethoden eingeführt. 7

mit 1 beginnt und nicht mit 0. Übergibt man eine Zeichenfolge, bezieht man sich auf die Spalte mit diesem Namen (z.b. rs.getdouble("gehalt");). Numerische Argumente sind zwar etwas effizienter, aber mit Zeichenfolgen ist der Code verständlicher und leichter zu pflegen. SQL- und Java-Datentypen sind nicht genau gleich. Jede get-methode führt eine sinnvolle Typumwandlung durch, wenn der Typ der Methode nicht dem Typ der Spalte entspricht. Z.B. können fast alle Typen als Strings dargestellt werden. Tabelle 1 gibt einen Überblick über die wichtigsten Typumwandlungen. SQL-Datentyp CHAR VARCHAR BIT INTEGER BIGINT REAL FLOAT DOUBLE BINARY DATE TIME Java-Datentyp String String boolean int long float double double byte[] java.sql.date java.sql.time Tabelle 1: Typabbildungen zwischen SQL und Java 5) Freigabe von Objekten Objekte, wie z.b. Connection, Statement oder ResultSet, welche nicht mehr gebraucht werden, sollten durch die Methode close freigegeben werden. Ein ResultSet wird üblicherweise nach Beenden der while-schleife geschlossen. Somit wird es sofort freigegeben und kann durch die automatische Speicherbereinigung entsorgt werden, was nebenbei auch DBMS-Ressourcen freimacht. Statement-Objekte werden oft am Ende der Methode geschlossen. Connection-Objekte werden meistens erst bei Beenden der Anwendung geschlossen, da diese ständig gebraucht werden. 2.3. SQLJ Es stellt sich die Frage, wieso man überhaupt SQLJ braucht. JDBC alleine reicht vollkommen aus. Es zeigen sich allerdings zwei Schwächen: 1. Der (SQL-relevante) Code wird lange und unhandlich. 2. Fehler innerhalb SQL-Operationen werden erst zur Laufzeit entdeckt. Wie wir sehen werden, löst SQLJ beide Probleme. Vom ersten Punkt und dessen Lösung können wir uns in Kapitel 3 überzeugen. 8

A. Zweck Java gehört zu den objektorientierten Programmiersprachen. SQL ist dagegen eine nichtprozedurale Sprache zur Definition und Manipulation von Daten in relationalen Datenbanken. SQLJ ist der ANSI-Standard 6 für die Einbettung von statischen SQL-Anweisungen in Java Programmen. Es ist das Produkt der Zusammenarbeit von Oracle, IBM, Sybase, Tandem, Informix, JavaSoft, XDB und Microsoft. B. Überblick SQLJ ersetzt JDBC nicht, sondern benutzt es weiterhin. Für statische SQL-Anweisungen, welche schon zum Entwicklungszeitpunkt bekannt sind, liefert SQLJ aber einen einfacheren und robusteren Weg. Für dynamische SQL-Anweisungen, welche z.b. während der Laufzeit von einem Endbenutzer kreiert werden, muss der bisherige JDBC-Weg verwendet werden. Natürlich können beide Möglichkeiten nebeneinander eingesetzt werden. JDBC und SQLJ sind also keine Substitute, sondern Komplementärprodukte. SQLJ-Anweisungen werden grundsätzlich mit #sql { SQL-Ausdruck }; gekennzeichnet. Java-Code mit solchen Anweisungen kann somit nicht mehr in einem herkömmlichen Java-Compiler übersetzt werden, sondern benötigt einen SQLJ-Translator. Abbildung 3 zeigt das Vorgehen im Überblick. Abbildung 3: Übersetzung eines SQLJ-Programms 6 seit 1999 9

Der Quellcode wird nicht in einer.java-datei erfasst, sondern in einer.sqlj-datei. Diese Datei wird von einem Präprozessor, dem SQLJ-Translator, übersetzt. Dabei werden die SQL- Operationen auf ihre Syntax und Semantik überprüft. Zusätzlich besteht die Möglichkeit des Online-Überprüfens, d.h. der Translator kann die Anweisungen gegen das Datenbankschema testen. Während der Übersetzung werden (mindestens) zwei Dateien generiert: 1. Eine Java-Quellcodedatei (.java-datei): Sie enthält a) die SQL-Anweisungen, welche durch Aufrufe an das SQLJ-Laufzeitsystems ersetzt wurden; und b) den normalen Quellcode des Programms. 2. Ein sogenanntes Profil (Datei mit der Endung.ser), welches eine Beschreibung der SQL-Anweisungen beinhaltet. Nun kann der generierte Java-Quellcode mit einem Standard-Compiler (z.b. javac aus dem JDK) übersetzt werden. Auch das Starten der Anwendung ist normal möglich. Das SQLJ- Laufzeitsystem wird dabei automatisch aufgerufen, wenn es sich um eine SQLJ-Anwendung handelt. Zur Verbindung mit der Datenbank wird der JDBC-Treiber benutzt. C. Hostausdrücke Der zentrale Bestandteil der Integration von SQL in Java als Wirtssprache bilden die sogenannten Hostausdrücke. Die einfachste Form davon sind die Hostvariablen. Das sind normale Java-Variablen, welche den Konventionen der Typenabbildung zwischen Java und SQL genügen (vgl. Tabelle 1). Es versteht sich von selbst, dass diese Variablen innerhalb des Blockes sichtbar sein müssen. Hostvariablen werden in SQLJ-Anweisungen mit einem vorangestellten Doppelpunkt gekennzeichnet. Z.B.: double salaer; String name = "Prevost"; #sql { SELECT Gehalt INTO :salaer FROM Angestellter WHERE Nachname = :name }; Neben Hostvariablen können auch Hostausdrücke verwendet werden. Das sind u.a.: Zuweisungen: z.b. Gehalt = Gehalt * (1.0 + bonus/100) Inkrement und Dekrement: z.b. i++ Methodenaufrufe: z.b. name.touppercase() Dabei müssen diese Ausdrücke innerhalb einer runden Klammer mit einem Doppelpunkt davor stehen. Als Beispiel: String[] namen = new String[] { "Prevost", "Scheff", "Knaller"}; double[] bonus = new double[] { 10.0, 5.0, 2.5 }; for (int i=0; i<namen.length; i++ ) { #sql { UPDATE Angestellter SET Gehalt = Gehalt * :(1.0 + bonus[i]/100) WHERE Nachname = :(namen[i].touppercase()) }; } 10

Doch noch nicht genug mit der Flexibilität von SQLJ. Es können auch gespeicherte Prozeduren und Funktionen als Hostausdrücke verwendet werden. Dabei werden die Schlüsselworte CALL für Prozeduren und VALUES für Funktionen benutzt. Das folgende Beispiel ruft die (eingebaute) SQL-Funktion SYSDATE() 7 auf und weist den Wert einer Variable zu: java.sql.date heute; #sql heute = { VALUES(SYSDATE()) }; System.out.println("Die Datenbank denkt, heute ist der " + heute); D. In or Out? Im vorherigen Abschnitt habe ich die Tatsache weggelassen, dass Hostvariablen (oder -ausdrücke) in drei verschiedenen Modi benutzt werden können. IN bezeichnet Werte, die an die Datenbank gesendet werde. Dagegen beschreibt OUT Variablen, die ihren Wert aus der Datenbank bekommen. INOUT umfasst beide. Normalerweise haben Hostausdrücke den Modus IN. Die Ausnahme sind Hostausdrücke in der SELECT INTO Anweisung, welche OUT-Variablen sind. In diesen Fällen ist der Modus implizit vorgegeben. In allen anderen Fällen, v.a. bei gespeicherten Prozeduren, muss der Modus explizit festgelegt werden. E. Iteratoren Hostausdrücke eignen sich nur für den Austausch einzelner Werte zwischen SQL und Java. Zur Speicherung von ganzen Ergebnismengen wird dagegen ein Iterator verwendet, ähnlich einem java.sql.resultset. Im Unterschied zum JDBC, muss ein Iterator vorher deklariert werden. Dabei wird zwischen zwei unterschiedlichen Arten unterschieden: Positionsiteratoren: Sie werden durch den (Java-)Datentyp der Spalte charakterisiert. Zum Abrufen der Werte wird die FETCH-Anweisung verwendet. Dies ist eine übliche Vorgehensweise auch in anderen Sprachen mit eingebettetem SQL. #sql iterator MyPosIter(String, double); Benannte Interatoren: Hier kann neben dem Datentyp auch der Bezeichner gewählt werden. Der Bezeichner liefert denn auch gerade noch den Namen für die Zugriffsmethode auf den jeweiligen Spaltenwert. JDBC-Programmier sollten sich unmittelbar mit dieser Art vertraut fühlen. #sql iterator MyNamedIter(String name, double gehalt); Dabei muss die Anzahl der Spalten der Ergebnisrelation mit der Anzahl der Attribute der Iteratoren übereinstimmen. In unserem Fall muss die Ergebnisrelation zweidimensional sein. Der SQLJ-Translator generiert aus der Iterator-Definition eine Iterator-Klasse mit dem angegebenen Namen. Z.B. ergibt sich für den Positionsiterator eine Klasse MyPosIter. Bei 7 Zumindest bei Oracle 11

den benannten Iteratoren wird zusätzlich noch für jede Spalte eine Zugriffsmethode geschaffen, also in unserem Beispiel zwei Methoden mit den Namen name() und gehalt(). 3. Vergleich Nun wissen wir genug, um SQLJ und JDBC zu vergleichen. Am Besten können wir das ganze anhand eines Beispiels machen. Wie schon erwähnt, muss bei SQLJ das Datenbankschema schon bekannt sein. Ich verwende folgende zwei Relationen: 1. Angestellter(Vorname, Nachname, AHV_Nr, Gehalt, Abt_Nr) 2. Abteilung(Abt_Name, Nr, Ort) Im Beispiel wird zuerst ein INSERT und danach ein SELECT ausgeführt. import java.sql.*; import sqlj.runtime.*; import sqlj.runtime.ref.*; public class SeminarExample { // Die beiden folgenden Variablen sind für die Abfrage vorgesehen String name = "Müller"; double salary = 4000.0; Connection con; public static void main(string[] args) throws SQLException { // Treiber registrieren, Verbindung herstellen usw. (Vgl. Seite 6) if (args[0].equals("jdbc")) jdbcexample(); else if (args[0].equals("sqlj")) sqljexample(); } public void jdbcexample() throws SQLException { // Zuerst INSERT durchführen // SQL-Anweisung als Objekt vorbereiten Statement stmt = con.createstatement(); // INSERT-Anweisung erstellen String command = "INSERT INTO Angestellter " + "VALUES ('Jussi', 'Prevost', 2606, 10000.0, 3)"; // Anweisung ausführen stmt.executeupdate(command); // Statement schliessen stmt.close(); // SELECT ausführen // Abfrage erstellen String query = "SELECT Vorname, Nachname, AHV_Nr, Gehalt, Ort " + "FROM Angestellter, Abteilung " + "WHERE Nachname=? AND " + "Gehalt>? AND " + "Abt_Nr=Nr"; 12

} // PreparedStatements vorbereiten und Hostvariablen einbinden PreparedStatement pstmt = con.preparedstatement(query); pstmt.setstring(1, name); pstmt.setint(2, salary); // Abfrage ausführen ResultSet rs = pstmt.executequery(); // und Resultate anzeigen while(rs.next()) { System.out.println("Vorname = " + rs.getstring(1) + " " + "Nachname = " + rs.getstring(2) + " " + "AHV_Nr = " + rs.getint(3) + " " + "Gehalt = " + rs.getdouble("gehalt") + " " + "Ort = " + rs.getstring("ort")); } // ResultSet- und Statement-Objekte schliessen rs.close(); pstmt.close(); public void sqljexample() throws SQLException { // Zuerst INSERT durchführen // INSERT-Anweisung in der SQLJ-Syntax erstellen #sql { INSERT INTO Angestellter(Vorname, Nachname, AHV_Nr, Gehalt, Abt_Nr) values('jussi', 'Prevost', 2606, 10000.0, 3) }; // SELECT ausführen // Iterator für das Speichern der Abfrage definieren #sql iterator MyIter(String FirstName, String Name, int AHV_NR, double Gehalt, String Ort); } } // Iterator-Objekt erstellen MyIter iter; // Abfrage ausführen und Ergebnis dem Iterator zuweisen #sql iter = { SELECT Vorname, Nachname, AHV_Nr, Gehalt, Ort FROM Angestellter, Abteilung WHERE Nachname = :name AND Gehalt> :salary AND Abt_Nr=Nr }; // Ergebnis Anzeigen while (iter.next()) { System.out.println("Vorname = " + iter.firstname() + " " + "Nachname = " + iter.name() + " " + "AHV_Nr = " + iter.ahv_nr()+ " " + "Gehalt = " + iter.gehalt() + " " + "Ort = " + iter.ort(); } // Iterator-Objekt freigeben iter.close(); 13

3.1. Verbindungsaufbau Der Verbindungsaufbau funktioniert in beiden Varianten gleich. Eine geschicktere Variante anstelle der manuellen Registrierung des Treibers, wäre die Verwendung der Systemeigenschaft jdbc.drivers. Dabei könnte auch die URL, der Benutzername und das Passwort in einer Eigenschaftsdatei (Datei mit der Endung.properties) gespeichert werden und bequem auf die Endbenutzer eingestellt werden. 3.2. Insert Eine Insert-Anweisung auf dem JDBC-Weg umfasst mehrere Schritte, welche den Code aufblähen: Zuerst muss ein Statement-Objekt erzeugt werden, dann ausgeführt und zum Schluss sollte es wieder geschlossen werden. SQLJ braucht hingegen nur eine Anweisung, welche (beinahe) die reine SQL-Anweisung in der SQLJ-Syntax beinhaltet. Es wird auch keine execute-methode gebraucht. Die Verwendung von SQLJ ist also viel einfacher, kürzer und deshalb auch einfacher zu Warten. 3.3. Select Bei der Select-Anweisung sieht es ähnlich aus. Die JDBC-Methode benötigt wieder mehrere Schritte: (Prepared)Statement-Objekt schaffen, Variablen zuweisen, ausführen, Ergebnis einem ResultSet zuweisen. Danach Ergebnis bearbeiten und zum Schluss ResultSet- und Statement-Objekte schliessen. Bei der SQLJ-Methode muss zuerst der Iterator für die Ergebnismenge definiert werden. Dies sieht auf den ersten Blick nach zusätzlicher Arbeit aus, ist es aber nicht. Denn ein solcher Iterator liefert intuitivere Zugriffsmethoden auf die einzelnen Ergebnisspalten, als diejenigen von ResultSet. Auch hier wird keine execute-methode verwendet. Zudem entfällt das Setzen der Platzhalter und Zuweisen der (Host-)Variablen durch Methodenaufruf. Die Host- Ausdrücke können direkt in der SQL-Anweisung verwendet werden. Das SQLJ-Verfahren ist wiederum kürzer und einfacher zu Bedienen. 3.4. Online-Überprüfung Bei SQLJ besteht die Möglichkeit, SQL-Anweisungen zur Übersetzungszeit anhand des Datenbankschemas zu prüfen. Dabei werden nicht schon die Daten benötigt, sondern das Schema mit den richtigen Attributen und Datentypen genügt. Eine solche Online- Überprüfung kann folgendermassen aussehen: sqlj user=jussi/seminar url=jdbc:odbc:seminardb SeminarExample.sqlj So werden SQL-spezifische Fehler schon zur Übersetzungszeit erkannt und können behoben werden. JDBC (bzw. der Java-Compiler) bietet keine solchen Möglichkeiten. 14

3.5. Geschwindigkeit Da SQLJ über JDBC mit einer Datenbank kommuniziert, kann es kaum schneller sein als JDBC alleine. In beiden Technologien besteht die Möglichkeit, Datenmanipulationsanweisungen zu sammeln und in Form eines Stapels (Batch) an die Datenbank zu senden. Abfragen kann man nicht in einem Stapel einbinden, da sie Ergebnismengen zurückliefern. Hat man z.b. 20 Tupel einzufügen, so würde man diese in einem Stapeln sammeln und dann als eine Transaktion an die Datenbank senden, anstatt alle 20 Anweisungen einzeln zu übermitteln. Die Vorteile liegen auf der Hand. 4. Zusammenfassung Programmierer, die in ihrer Anwendung eine Datenbankanbindung brauchen, benötigen aus meiner Sicht JDBC und SQLJ. Dabei wird eine Anwendung geschaffen, die sowohl plattformunabhängig wie auch DBMS-unabhängig ist. JDBC alleine würde genügen, weist aber zwei Schwächen aus: 1. Der Quellcode wird lange und unübersichtlich, was Fehlersuche und Unterhalt erschwert. 2. Fehler innerhalb von SQL-Anweisungen werden erst zur Laufzeit erkannt. SQLJ löst beide Probleme folgendermassen: 1. SQLJ erlaubt die Verwendung von Hostausdrücken direkt in SQL-Anweisungen, was den Code kürzer und einfacher macht. 2. Der SQLJ Translator überprüft die Syntax und Semantik von SQL-Anweisungen. Es besteht die Möglichkeit die Anweisungen gegen das Datenbankschema zu prüfen, wobei SQL-Fehler frühzeitig entdeckt und behoben werden können. Voraussetzung für den Einsatz von SQLJ ist, dass die Datenbank schon vorhanden ist, oder zumindest das Schema. Ansonsten wäre es nicht möglich eine Online-Überprüfung vorzunehmen, oder sogar Abfragen vorzubereiten! Allgemein kann man sagen, dass JDBC und SQLJ komplementäre Technologien sind, weil: SQLJ benutzt zur Kommunikation mit der Datenbank JDBC. JDBC wird für dynamisches SQL gebraucht, wo die Anweisungen erst zur Laufzeit bekannt werden. JDBC und SQLJ können miteinander eingesetzt werden. 15

Literaturverzeichnis Estermann, Conny. SQLJ., Universität Zürich, Sommersemester 2001 Horstmann, Cay S. und Cornell, Gary. Core Java 2 Advanced Features. Prentice Hall, 1999 JDBC API Documentation. http://java.sun.com/j2se/1.3/docs/guide/jdbc Khan, Salman & Kurian, Thomas & Wright, Brian. SQLJ: It s Javalicious!. http://technet.oracle.com/, 1999 Lagler, Severin. JDBC und JavaBlend., Universität Zürich, Sommersemester 2001 Rohwelder, Ekkehard. SQLJ: Tricks, Traps and Gems. http://technet.oracle.com/, 1999 Saake, Gunter und Sattler, Kai-Uwe. Datenbanken & Java: JDBC, SQLJ und ODMG. dpunkt.verlag, 2000 SQLJ Konsortium. http://www.sqlj.org/ SQLJ Standards. http://otn.oracle.com/tech/java/sqlj_jdbc/htdocs/standards.html Taylor, Blair und Woodger, James. SQLJ: An Easier Way to Access SQL Data. Java Enterprise Developer online (http://www.pinnaclepublishing.com/je/jemag.nsf/0/8c6831ab722aad8e85256981 006F42A0), November 2000 16