Problemseminar - Datenbankeinsatz im Internet

Java und Datenbanken

 

Bearbeiter:

Alexander Dietzsch

 

Betreuer:

Dr. Sosna

 

1 Einführung

2 JDBC

2.1 JDBC und SQL

2.2 zweischichtige – und dreischichtige Modelle

2.3 JDBC Bestandteile

2.4 JDBC Treibertypen

2.5 Datenbankverbindung

2.6 SQL-Statements

2.6.1 ExecuteQuery

2.6.2 ExecuteUpdate

2.6.3 PreparedStatement

2.6.4 CallableStatement

2.7 Transaktionen

2.8 Ergebnisverarbeitung

2.9 Abbildung von JDBC- und SQL-Datentypen

2.10 Datenbank Metadaten

3 SQLJ

3.1 SQLJ Teil 0: Embedded SQL in Java

3.1.1 Verbindungskontext

3.1.2 Ausführungskontext

3.1.3 Host Variablen und Ausdrücke

3.1.4 Aufruf gespeicherter Routinen

3.1.5 Cursor

3.2 SQLJ Teil 1: Java Methoden als SQL Prozeduren

3.2.1 Installation von Java Klassen in SQL

3.2.2 Vergabe von SQL Namen für Funktionen und Prozeduren

3.2.3 Überladen von Java Methoden und SQL Namen

3.2.4 Verarbeitung von Ausgabeparameter

3.2.5 Verarbeitung von Resultsets

3.2.6 Vergabe von SQL Zugriffsrechen

3.2.7 Fehlerbehandlung

3.2.8 Deployment Descriptors

3.2.9 Verwendung von Java Klassen als SQL Prozeduren

3.3 SQLJ Teil 2: Java Klassen als SQL Datentypen

3.3.1 Vergabe von SQL Namen für SQL Datentypen

3.3.2 Verwendung von Java Klassen als SQL Datentypen

3.3.3 Kollabierende Subklassen

4 Java Blend

5 Zusammenfassung

6 Literaturverzeichnis

 

Einführung

 

Mit der Verbreitung des Internets in den letzten Jahren ist auch der Wunsch gewachsen über das Internet bzw. Intranet Zugriff auf Datenbanken zu bekommen.

Java ist eine hervorragenden Sprachbasis für Datenbankanwendungen, weil es robust, sicher, einfach zu nutzen, einfach zu verstehen und in einem Rechnernetz automatisch ladbar ist [HC97]. Darüber hinaus bietet Java die Vorteile, daß die Anwendungen auf den verschiedensten Plattformen laufen, die Entwicklungszeit für neue Datenbankanwendungen kürzer werden und die Installation stark vereinfacht wird. Dies hat dazu geführt, daß sich Java als Programmiersprache für Datenbankanwendungen im Internet und Intranet durchgesetzt hat.

 

JDBC

 

Die Entwickler von Java haben bereits sehr früh erkannt, daß in der Industrie ein starkes Interesse an einer Schnittstelle von Java zu Datenbanken besteht. Um zu verhindern, daß einige Hersteller eigene Datenbank-APIs entwickeln, wurde Ende 1995 damit begonnen eine solche Schnittstelle zu entwickeln. Dies war die Geburtsstunde von JDBC. Mit JDK 1.2 wurde 1998 die aktuelle Version JDBC 2.0 veröffentlicht.

Ziel war es eine low-level API zu definieren, die eine Basisfunktionalität von SQL zur Verfügung stellt. Hierbei baute die Arbeit auf X/Open SQL CLI (Call Level Interface) und ODBC (Object Database Connectivity) auf.

JDBC ist eine in Java programmierte API, die SQL-Anweisungen ausführt. Sie besteht aus einer Menge von Klassen und Schnittstellen, die sich im Paket java.sql befinden.

Überblick über das Paket java.sql

Schnittstellen: Klassen: Ausnahmen:
CallableStatement Date DataTruncation
Connection DriverManager SQLException
DatabaseMetaData DriverPropertyInfo SQLWarning
Driver Time  
PreparedStatement Timestamp  
ResultSet Types  
ResultSetMetaData    
Statement    

JDBC bietet Klassen und Methoden zur Unterstützung von:

 

JDBC und SQL

 

JDBC als Basis-API zur Ausführung von SQL-Anweisungen unterstützt den ANSI SQL-2 Entry Level. Jeder Hersteller von Datenbanksystemen, der für JDBC Treiber entwickeln möchte, muß dafür sorgen, daß jeder JDBC-konforme Treiber diesen Standard unterstützt.

Leider gibt es bei der Umsetzung des SQL-Standard durch die Hersteller von Datenbanksystemen noch einige Probleme. Zwar unterstützen heute alle gängigen DBMS die Grundfunktionalität von SQL, aber speziell bei Datentypen, gespeicherten Prozeduren und äußeren Verbundoperationen gibt es zwischen den verschiedenen Systemen gravierende Unterschiede bei Implementation und Syntax. Dies bedeutet für JDBC eine Reihe von Problemen.

Aus diesem Grund gibt es drei Arten diese Probleme zu lösen:

Die wichtigsten SQL-Befehle, die von JDBC unterstützt werden, sind:

 

zweischichtige – und dreischichtige Modelle

 

Beim Zugriff einer Java Anwendung auf eine Datenbank sind das zwei- und das dreischichtige Modell zu unterscheiden.

Im zweischichtigen Modell (two-tier model) kommuniziert die Java Anwendung direkt mit der Datenbank. Dies erfordert, daß der JDBC-Treiber mit dem spezifischen DBMS kommunizieren kann. Bei diesem Modell werden die SQL-Anweisungen der Anwendung an die Datenbank gesendet und die Ergebnisse zurückgesendet. Diese Variante wird als Client/Server-Konfiguration bezeichnet.

Im dreischichtigen Modell (three-tier model) werden die Anfragen an eine mittlere Schicht übergeben, die ihrerseits SQL-Anweisungen an die Datenbank sendet. Die Datenbank verarbeitet die Anweisungen und sendet die Ergebnisse zurück an die mittlere Schicht, die diese zurück an die Anwendung schickt. Vorteil dieser Variante ist, daß der Zugriff auf die Datenbank stärker kontrolliert werden kann. Ein weiterer Vorteil der mittleren Schicht ist die Verwendung einer höheren API auf Seiten der Anwendung, die dann durch die mittlere Schicht in eine niedrigere API umgesetzt werden kann. Da die mittlere Schicht typischerweise in Sprachen wie C oder C++ programmiert ist, ist auch eine höhere Performance gegenüber dem zweischichtigen Modell zu erwarten.

 

JDBC Bestandteile

 

JDBC besteht aus zwei Teilen:

Zentraler Teil von JDBC ist der JDBC-Treibermanager. Seine Aufgabe ist es die Java Anwendung mit dem korrekten JDBC-Treibers zu verbinden.

Der andere wichtiger Teil von JDBC ist die JDBC-ODBC-Brücke, die es Java Anwendungen ermöglicht ODBC-Treiber als JDBC-Treiber zu verwenden. Sie hat dafür gesorgt, daß bereits sehr früh eine Anbindung für die wichtigsten Datenbanksysteme bestand. Auch der Zugriff auf weniger populäre DBMS , für die eine Implementierung von JDBC-Treibern nicht geplant ist, ist dadurch möglich. Damit hat dieser Teil hat stark zur Akzeptanz von JDBC beigetragen.

 

JDBC Treibertypen

 

Bei den JDBC-Treibern lassen sich vier Kategorien von Treibern unterscheiden:

Mit Hilfe des JDBC-ODBC-Brückentreibers ist es möglich auf eine ODBC-fähige Datenbank über JDBC zuzugreifen, ohne einen eigenen JDBC-Treiber zur Verfügung zu haben. Hierbei ist zu beachten, daß der ODBC-Binärcode auf jeden Client-Rechner geladen werden muß. Diese Art von Treiber eignet sich darum besonders für Unternehmen, wo die Installation der Software auf dem Client kein Problem darstellt.

Diese Art Treiber übersetzt die JDBC-Aufrufe in Aufrufe einer nativen Datenbank-API. Aber auch hier ist es notwendig, daß wie beim JDBC-ODBC-Brückentreiber Binärcode auf jeden Client-Rechner geladen werden muß. Dies führt in der Regel zu Performanceverlusten.

Diese Art Treiber übersetzt die JDBC-Aufrufe in ein vom DBMS unabhängiges Netzprotokoll, das dann durch einen Server in ein DBMS-Protokoll übersetzt wird. Diese Middleware erlaubt es dem Client die verschiedensten Datenbanken anzusprechen. Damit ist diese Art von Treibern die flexibelste JDBC-Lösung.

Diese Art der Treiber übersetzt die JDBC-Aufrufe direkt in das von dem DBMS verwendeten Netzprotokoll. Da damit der Client-Rechner direkt mit dem DBMS-Server kommuniziert stellt dies wohl die effizienteste Lösung dar. Damit ist es eine exzellente Lösung für das Internet.

 

Datenbankverbindung

 

Am Anfang einer Datenbankverbindung steht

  • Damit ein Treiber geladen werden kann ist es nötig, daß der JDBC Treibermanager erfährt, welche Treiber verfügbar sind.

    Dies läßt sich auf zwei Arten realisieren:

    1. Bei der Initialisierung der Klasse DriverManager wird in der Systemeinstellung nach dem Eintrag sql.drivers gesucht, der eine Liste der registrierten Treiber enthält. Anschließend lädt der Treibermanager jeden dort aufgeführten Treiber.
    2. Im Programm läßt sich mit Hilfe der Methode Class.forName explizit ein Treiber laden.

    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

    // Laden des JDBC-ODBC-Brückentreibers

  • Durch Aufruf der Methode DriverManager.getConnection der JDBC Treibermanager erhält man ein Objekt der Klasse Connection. Dieses Objekt repräsentiert die Verbindung zu einer beliebigen JDBC-fähigen Datenbank. Die Methode DriverManager.getConnection erwartet als Argument eine URL der Struktur jdbc:<Unterprotokoll>:<Untername>. Die JDBC Treibermanager versucht einen Treiber zu finden, der die Verbindung zur Datenbank, die durch die URL repräsentiert wird, herstellt. Bei der Suche nach dem Treiber wird jeder Treiber in der Liste sql.drivers der Reihe nach ausprobiert, bis eine Verbindung hergestellt werden konnte. Beim Öffnen der Verbindung ist es möglich Argumente, wie "user" oder "password", zu übergeben.
  • Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    // Aufbau der Verbindung zur Datenbank Test

     

    SQL-Statements

     

    Für die Ausführung von SQL-Anweisungen ist es nötig, daß ein SQL-Statement erzeugt wird, dem die SQL-Anweisung übergeben wird und das diese an die Datenbank sendet. Das Objekt der Klasse Statement wird dabei auf einer bestimmten Datenbankverbindung erzeugt.

    Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    // Aufbau der Verbindung zur Datenbank Test

    Statement stmt = con.createStatement();

    // erzeugen eines Statement-Objekts

    Für die verschiedenen Arten von SQL-Anweisungen gibt es vier verschiedene Arten von Statements:

    ExecuteQuery PreparedStatement
    ExecuteUpdate CallableStatement

    Allen ist dabei gemein, daß ihnen ein String mit einem syntaktisch korrekten SQL-Statement übergeben wird. Sie unterscheiden sich lediglich durch die Ergebnismenge und durch Ein-/Ausgabeparameter.

     

    ExecuteQuery

     

    Die Methode executeQuery wird dazu verwendet, um Daten aus einer Datenbank zu selektieren. Das Ergebnis der Methode ist ein Objekt der Klasse ResultSet.

    Beispiel:

    Statement stmt = con.createStatement();

    // erzeugt ein Statement auf der Verbindung

    ResultSet rs = stmt.executeQuery("SELECT * FROM Table");

    // führt das SQL-Statement aus und übergibt das

    // Ergebis an das ResultSet rs

     

    ExecuteUpdate

     

    Die Methode executeUpdate wird dazu verwendet, um Manipulationen auf der Datenbank auszuführen. SQL-Statements, wie INSERT, UPDATE, DELETE lassen sich nur mit Hilfe dieser Methode ausführen. Die Anzahl der manipulierten Datensätze wird als Ergebnis der Methode zurückgegeben.

    Beispiel:

    Statement stmt = con.createStatement();

    // erzeugt ein Statement auf der Verbindung

    int i = stmt.executeUpdate("DELETE FROM Table");

    // führt das SQL-Statement aus

     

    PreparedStatement

     

    Die Klasse PreparedStatement bietet sich dann an, wenn ein SQL-Statement mehrfach mit verschiedenen Parameterwerten ausgeführt werden soll. Vorteil dieser Klasse ist, daß bei der Erzeugung des Objekts das Statement an die Datenbank gesendet und dabei gegebenenfalls optimiert wird. Dies bedeutet in der Regel einen Performancegewinn.

    Für jeden Parameter in einem SQL-Statement wird der Platzhalter ? verwendet. Die Klasse PreparedStatement verfügt über Methoden setXXX, die für jeden Datentyp das Setzen der Parameter ermöglichen (XXX steht für den Datentyp).

    Nachdem die Parameter gesetzt wurden läßt sich das SQL-Statement durch Aufruf der Methoden execute, executeQuery oder executeUpdate ausführen.

    Beispiel:

    PreparedStatement stmt = con.prepareStatement("UPDATE Table SET x = ? WHERE y = ?");

    // erzeugt ein PreparedStatement und übergibt ihm

    // ein SQL-Statement mit zwei Parametern

    stmt.setInt(1, 123);

    // setze den ersten Parameter auf 123

    stmt.setString(2, "Hi");

    // setze den zweiten Parameter auf "Hi"

    stmt.executeUpdate();

    // führe das SQL-Statement aus

     

    CallableStatement

     

    Die Klasse CallableStatement wird zur Ausführung von gespeicherten Prozeduren benutzt. CallableStatement ist hierbei von PreparedStatement abgeleitet. Anders als die Basisklasse verfügt CallableStatement aber über Ein- und Ausgabeparameter. Das füllen der Eingabeparameter funktioniert wie bei PreparedStatement. Für die Verwendung eines Ausgabeparameters ist es nötig, daß der entsprechende Parameter mit dem Typ registriert wird. Für das registrieren der Ausgabeparameter wird die Methode registerOutParameter verwendet.

    Beispiel:

    CallableStatement stmt = con.prepareCall("{call Test(?, ?)}");

    // Aufruf der stored procedure mit zwei Ausgabe -

    // parametern

    stmt.registerOutParameter(1, java.sql.Types.TINYINT);

    // registriert den ersten Parameter als Integer

    stmt.registerOutParameter(2, java.lang.String);

    // registriet den zweiten Parameter als String

    stmt.executeUpdate();

    // führe das SQL-Statement aus

    byte x = stmt.getByte(1);

    // liest den ersten Parameter aus

    String y = stmt.getString(2);

    // liest den zweiten Parameter aus

     

    Transaktionen

     

    JDBC unterstützt Transaktionen und verwendet standardmäßig einen Auto-Commit- Modus. Dies bedeutet, daß jedes Statement als separate Transaktion ausgeführt wird. Für die Ausführung mehrerer Statements innerhalb einer Transaktion muß dieser Mechanismus ausgeschaltet werden. Dazu wird der Aufruf Connection.setAutoCommit(false) verwendet. Anschließend muß eine Transaktion mit den Methoden Connection.commit und Connection.rollback explizit abgeschlossen werden.

    Beispiel:

    Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    Statement stmt = con.createStatement();

    try {

    con.setAutoCommit(false);

    // autocommit Modus ausschalten

    stmt.executeUpdate(...);

    // Statement

    stmt.executeUpdate(...);

    // Statement

    con.commit();

    // bei Erfolg Transaktion abschließen

    } catch (SQLException e) {

    con.rollback();

    // bei Fehler Transaktion rückgängig machen

    }

     

    Ergebnisverarbeitung

     

    Das Ergebnis einer Anfrage an die Datenbank ist ein Objekt der Klasse ResultSet. Die Struktur dieses Objekts ist eine Tabelle aus einer Anzahl von Datensätzen und den selektierten Spalten. Um die Daten des Ergebnis zeilenweise auszulesen, gibt es in der Klasse ResultSet die Methode next. Mit dieser Methode bewegt man den Ergebniscursor jeweils um eine Zeile weiter. Jede Zeile des Ergebnis enthält Spalten unterschiedlichen Typs. Deshalb stellt die Klasse ResultSet für jeden in JDBC verfügbaren Datentyp entsprechende Methoden getXXX zum Auslesen zur Verfügung. Bei Verwendung der Methoden ist es nötig, daß entweder der Name der Spalte oder die Nummer der Spalte als Argument übergeben wird. GetObject nimmt unter den Methoden eine speziell Rolle ein, da sie als Container für beliebige Daten dienen kann deren Typ nicht bekannt ist.

    Arten der getXXX()-Methoden:

    GetByte GetShort
    GetInt GetLong
    GetFloat GetDouble
    GetBigDecimal GetBoolean
    GetString GetByte
    GetDate GetTime
    GetTimestamp GetAsciiStream
    GetUnicodeStream GetBinaryStream
    GetObject  

    Beispiel:

    Statement stmt = con.createStatement();

    // erzeugt ein Statement auf der Verbindung

    ResultSet rs = stmt.executeQuery("SELECT * FROM Table");

    // schickt ein SQL-Statement an die Datenbank

    // und übergibt das Ergebnis an das ResultSet rs

    while (rs.next()) // solange ein Datensatz im ResultSet ist

    {

    String x = rs.getString(1);

    // liest die erste Spalte als String aus

    Int y = rs.getInt("number");

    // liest die Spalte number als integer aus

    }

     

    Abbildung von JDBC- und SQL-Datentypen

     

    Bei der Arbeit mit einer Datenbank ist das Thema "Abbildung von Datentypen" schon immer ein ganz wichtiger Punkt gewesen, so auch bei Java und JDBC. Grund hierfür ist, daß Java und SQL nicht die selben Datentypen bereitstellen. Darum muß dafür gesorgt werden, daß die Daten korrekt abgebildet werden. Das hat nicht unbedingt zu bedeuten, daß die Abbildung von Java- und SQL-Datentypen isomorph sein muß. Ein Beispiel ist zum Beispiel der Java-Datentyp String, der nicht vollständig auf SQL-Datentyp CHAR abgebildet werden kann.

    Bei Date, Time und Timestamp handelt es sich um spezielle Java Datentypen. Sie wurden speziell für JDBC definiert. Der Grund dafür liegt in der Definition der ursprünglichen Datumstypen in Java, die nicht zu den SQL-Typen paßten.

    Bei einer fehlerhaften Abbildung der Datentypen wird entweder eine Warnung oder eine Exception ausgelöst.

    Abbildung von SQL-Datentypen auf Java-Datentypen:

    SQL Typ Java Typ
    CHAR String
    VARCHAR String
    NUMERIC Java.math.BigDecimal
    DECIMAL Java.math.BigDecimal
    BIT Boolean
    TINYINT Byte
    SMALLINT Short
    INTEGER Int
    BIGINT Long
    REAL Float
    FLOAT Double
    DOUBLE Double
    BINARY Byte[]
    VARBINARY Byte[]
    LONGVARBINARY Byte[]
    DATE Java.sql.Date
    TIME Java.sql.Time
    TIMESTAMP Java.sql.Timestamp

    Abbildung von Java-Datentypen auf SQL-Datentypen:

    Java Typ SQL Typ
    String VARCHAR oder LONGVARCHAR
    java.math.BigDecimal NUMERIC
    Boolean BIT
    Byte TINYINT
    Short SMALLINT
    Int INTEGER
    Long BIGINT
    Float REAL
    Double DOUBLE
    byte[] VARBINARY oder LONGVARBINARY
    java.sql.Date DATE
    java.sql.Time TIME
    java.sql.Timestamp TIMESTAMP

     

    Datenbank Metadaten

     

    In der Regel geht man davon aus, daß der Programmierer über das zugrundeliegende Datenbankschema Bescheid weiß. In vielen Fällen wird aber ein dynamischer Datenbankzugriff benötigt, weil Informationen über das DBMS und das Schema der Datenbank fehlen. Um Anwendungen zu programmieren, die unabhängig von der konkreten Struktur einer bestimmten Datenbank arbeiten, werden dafür Strukturinformationen benötigt.

    JDBC stellt hierfür die beiden Klassen ResultSetMetaData und DatabaseMetaData zur Verfügung.

    Mit der Klasse ResultSetMetaData ist es möglich, Informationen über die Struktur eines ResultSet Objekts zu erhalten. Dazu wird die Methode getMetaData der Klasse ResultSet verwendet.

    Beispiel:

    Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    // Aufbau der Verbindung zur Datenbank Test

    Statement stmt = con.createStatement();

    // erzeugen eines Statement Objekts

    ResultSet rs = stmt.executeQuery("SELECT * FROM Table");

    // Ausführung einer SQL-Anweisung

    ResultSetMetaData rsmd = rs.getMetaData();

    // Bindung des ResultSet Objekts mit einem Objekt

    // vom Typ ResultSetMetaData

    Mit Hilfe der Methoden getColumnCount, getColumnLabel, getColumnName, getColumnType, getTableName, getColumnDisplaySize und weiterer Methoden lassen sich detaillierte Informationen zum Typ und den Eigenschaften jeder Spalte einer Ergebnismenge abrufen.

    Beispiel:

    Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    // Aufbau der Verbindung zur Datenbank Test

    Statement stmt = con.createStatement();

    // erzeugen eines Statement Objekts

    ResultSet rs = stmt.executeQuery("SELECT * FROM Table");

    // Ausführung einer SQL-Anweisung

    ResultSetMetaData rsmd = rs.getMetaData();

    // Bindung des ResultSet Objekts mit einem Objekt

    // vom Typ ResultSetMetaData

    while (rs.next()) {

    for (int i = 0; i < rsmd.getColumnCount(); i++) {

    Object temp = rs.getObject(i);

    Sysem.out.println(temp.toString());

    }

    }

    Ähnlich wie ResultSetMetaData über eine Ergebnismenge Informationen einholen kann, so kann die Klasse DatabaseMetaData Informationen über die verwendete Datenbank einholen. Dazu wird die Methode getMetaData der Klasse Connection verwendet.

    Beispiel:

    Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    // Aufbau der Verbindung zur Datenbank Test

    DatabaseMetaData dbmd = con.getMetaData();

    // Bindung des Connection Objekts mit einem

    // Objekt vom Typ DatabaseMetaData

    Die Klasse DatabaseMetaData bietet eine Vielzahl von Methoden (mehr als 130 Methoden), um auf Informationen zuzugreifen. Nach ihrem Rückgabewert lassen sich die Methoden in vier Kategorien unterteilen:

    Einige ausgewählte Methoden sind z.B. getCatalogs, getColumns, getDriverName, getMaxConnections, getStringFunctions, getURL, isReadOnly, getSQLKeywords, supportsANSI92FullSQL, supportsFullOuterJoins.

    Beispiel:

    Connection con = DriverManager.getConnection("jdbc:odbc:Test", null, null);

    // Aufbau der Verbindung zur Datenbank Test

    DatabaseMetaData dbmd = con.getMetaData();

    // Bindung des Connection Objekts mit einem

    // Objekt vom Typ DatabaseMetaData

    boolean ANSI = dbmd.supportsANSI92FullSQL();

    // liefert Wahrheitswert, ob DBMS SQL 92

    // unterstützt

     

    SQLJ

     

    1997 gründete sich ein Konsortium verschiedener Firmen der IT-Branche, mit dem Ziel, die Zusammenarbeit von Java und relationalen Datenbankbanken zu verbessern. Zu den beteiligten Firmen gehören Compaq (Tandem), IBM, Informix, Micro Focus, Microsoft, Oracle, Sun und Sybase.

    Das Ziel von SQLJ wurde in drei Teile gegliedert:

    Einbindung von statischen SQL Statements in ein Java-Programm

    Nutzung von statischen Java Methoden als SQL Stored Procedures

    Verwendung von Java Klassen als SQL Abstract Data Types

    Bei der Implementierung von SQLJ wird auf JDBC als low level API aufgesetzt.

     

    SQLJ Teil 0: Embedded SQL in Java

     

    Teil 0 von SQLJ erlaubt die Einbindung von statischen SQL Statements in Java. Dabei funktioniert es auf die selbe Weise, wie es SQL 92 erlaubt, SQL Statements in C und COBOL einzubetten.

    Mit der Arbeit an Embedded SQL wurde vor den Teilen 1 und 2 begonnen. Ende 1998 ist SQLJ Teil 0 von der ANSI standardisiert und unter ANSI X3.135.10:1998 veröffentlicht worden. SQLJ Teil 1 und 2 sind im Augenblick als Working Drafts veröffentlicht worden und sollen im Laufe des Jahres 1999 standardisiert werden.

    Beispiel nach [EM98]:

    try {

    #sql {

    DELETE

    FROM employee

    WHERE emp_id = 17

    };

    // SQLJ Statement

    }

    catch (SQLException sqe) {

    System.out.println(sql.getMessage());

    }

    Für die Verwendung von SQLJ ist ein Übersetzer nötig. Der Übersetzer sucht die eingebetteten SQL Statements und ersetzt sie durch JDBC Statements, die diese ausführen. Das Ergebnis dieser Übersetzung ist ein Java Programm, daß normal kompiliert werden kann.

    Während der Laufzeit des Übersetzers ist es möglich, die Syntax und Semantik der SQL Anweisungen zu überprüfen. Dies kann sowohl offline, als auch online auf der Datenbank geschehen.

    Darüber hinaus ist es möglich, daß die Hersteller von DBMS sogenannte custumizer zur Verfügung stellen. Diese Tools erzeugen aus den SQLJ Statements datenbankspezifische SQL Statements (binaries oder profiles). Der generierte Code wird Teil der SQLJ Applikation. Zur Laufzeit wird für das verwendete DBMS entschieden, ob eine entsprechende costumization existiert, ansonsten wird der originale JDBC Code verwendet.

     

    Verbindungskontext

     

    Ein Connection Context Objekt wird verwendet, um ein SQL Statement mit einer bestimmten Datenbankverbindung zu verknüpfen. Connection Context kann dabei explizit oder implizit verwendet werden. Bei der Ausführung eines Statements wird ein Standard Connection Context verwendet, wenn nicht explizit ein Connection Context benutzt wird. Anwendungen mit mehreren Datenbankverbindungen müssen explizite Connection Context Objekte benutzen. Mit Hilfe der Methode ConnectionContext.getDefaultContext kann auf den Standard Connection Context zugegriffen werden.

    Beispiel nach [EM98]:

    #sql context EmpContext;

    // erzeugt Klasse von Connection Context

    String url = "jdbc:sybase:Tds:localhost:2638";

    EmpContext empCtxt = new EmpContext(url, "dba", "sql", false);

    // erzeugt Objekt von der Klasse EmpContext

    #sql [empCtxt] {

    DELETE

    FROM employee

    WHERE emp_id = 17

    };

    // Verwendung des Connection Contexts für die

    // Ausführung der SQL-Anweisung

     

    Ausführungskontext

     

    Ein Execution Context Objekt ermöglicht die Ausführung des Statements zu kontrollieren und Informationen über die Ausführung zu erhalten. Wie Connection Context kann der Execution Context implizit oder explizit verwendet werden. Ein Connection Context besitzt einen Standard Execution Context, dieser wird verwendet, wenn kein expliziter Execution Context spezifiziert wurde. Mit Hilfe der Methode ConnectionContext.getExecutionContext kann darauf zugegriffen werden.

    Beispiel nach [EM98]:

    Sqlj.runtime.ExecutionContext execCtxt = new sqlj.runtime.ExecutionContext();

    // erzeugt Objekt der Klasse ExecutionContext

    #sql [empCtxt, execCtxt]

    {

    DELETE

    FROM employee

    WHERE emp_id = 17

    };

    // Verwendung des Connection Contexts für die

    // Ausführung der SQL-Anweisung

    System.out.println("Deleted " + execCtxt.getUpdateCount() + " rows.");

    // gibt die Anzahl der geänderten Datensätze aus

     

    Host Variablen und Ausdrücke

     

    SQLJ Teil 0 ermöglicht die Verwendung von Host Variablen und Ausdrücken. Die Art der Parameter (IN, OUT, INOUT) wird implizit durch ihre Verwendung spezifiziert. Die

    Syntax der Host Variablen ist folgende:

    <host expression> ::=

    : [ <parameter mode> ] <expression>

    <parameter mode> ::= IN | OUT | INOUT

    <expression> ::= <variable> | ( <complex expression> )

    Beispiel nach [EM98]:

    int id;

    #sql { SELECT emp_id

    INTO :id

    FROM employee

    WHERE emp_fname LIKE :(argv[0] + '%')

    };

    // Verwendung von Host Variablen

    // id als Ausgabeparameter und

    // (argv[0] + '%') als Eingabeparameter

    System.out.println("Employee id " + id);

    // gibt die ID des Mitarbeiters aus

     

    Aufruf gespeicherter Routinen

     

    Um gespeicherte Routinen aufzurufen wird das SQL CALL Statement benutzt.

    Beispiel nach [EM98] (Prozedur):

    int count = 0;

    #sql { CALL emp_count (:in (argv[0]),

    :in (argv[1]),

    :out count)

    };

    // Aufruf der gespeicherten Prozedur emp_count

    // mit Übergabe von zwei Eingabeparametern und

    // einem Ausgabeparameter

    System.out.println("The result is " + count);

    // gibt die Anzahl der Mitarbeiter aus

    Beispiel nach [EM98] (Funktion):

    int count = 0;

    #sql { count = { VALUES emp_count2

    (:in (argv[0]),

    :in (argv[1])

    )

    }

    };

    // Aufruf der gespeicherten Prozedur emp_count2

    // mit Übergabe von zwei Eingabeparametern,

    // Rückgabewert wird Variable count übergeben

    System.out.println("The result is " + count);

    // gibt die Anzahl der Mitarbeiter aus

     

    Cursor

     

    Das wohl am häufigsten verwendete Statement in Anwendungen ist das SELECT Statement. Um auf das Ergebnis eines solchen Statements zuzugreifen wird ein Cursor (iterator) verwendet. SQLJ Teil 0 unterstützt zwei Arten von Iteratoren:

    Beispiel nach [EM98] (named iterator):

    #sql iterator Employee

    (

    int emp_id,

    String emp_lname,

    Java.sql.Date start_date

    );

    Employee emp;

    #sql emp = { SELECT emp_lname, emp_id, start_date

    FROM employee

    WHERE emp_fname LIKE 'C%'

    };

    while (emp.next()) {

    System.out.println(emp.start_date() + ", " + emp.emp_id() + ", " + emp.emp_lname().trim());

    }

    emp.close();

    Beispiel nach [EM98] (positioned iterator):

    #sql iterator Employee (int, String, String);

    int emp_id = 0;

    String emp_lname = null;

    String emp_fname = null;

    Employee emp;

    #sql emp = { SELECT emp_id, emp_lname, emp_fname

    FROM employee

    WHERE emp_fname LIKE 'C%'

    };

    while (true) {

    #sql { FETCH emp INTO :emp_id,

    :emp_lname,

    :emp_fname };

    if (emp.endFetch()) break;

    System.out.println(emp_fname.trim() + " "

    + emp_lname.trim()

    + ", " + emp_id

    );

    }

     

    SQLJ Teil 1: Java Methoden als SQL Prozeduren

     

    Teil 1 von SQLJ ermöglicht es in einem DBMS statische Java Methoden als SQL stored procedures zu benutzen. Funktionalität und Verwendung dieser Java Methoden ist dabei identisch zu SQL stored procedures.

    Damit Java Methoden in SQL benutzt werden können, muß zuerst die Java Klasse installiert und anschließend daraus eine SQL Prozedur bzw. Funktion definiert

    werden.

    Vor der Installation der Java Klassen müssen diese kompiliert und anschließend in ein JAR File gepackt werden.

    Beispiel nach [SQLJ98/2]:

    public class Routines1 {

    public static Integer region(String s) throws SQLException {

    if (s =="MN" || s == "VT") return 1;

    else if (s == "FL" || s == "GA" ||s == "AL") return 2;

    else if (s == "CA" || s == "AZ" || s== "NV") return 3;

    else return 4;

    }

    public static void correctStates(String oldSpelling, String newSpelling) throwsSQLException {

    Connection con =

    DriverManager.getConnection(JDBC:DEFAULT:CONNECTION");

    PreparedStatement stmt =

    con.prepareStatement("UPDATE emps SET state = ? WHERE state = ?");

    stmt.setString(1, newSpelling);

    stmt.setString(2, oldSpelling);

    stmt.executeUpdate();

    con.close();

    return;

    }

    }

     

    Installation von Java Klassen in SQL

     

    Um Java Klassen in SQL zu nutzen wird als erstes das jar file durch Aufruf der Prozedur sqlj.install_jar in das DBMS geladen.

    Für das Beispiel nach [SQLJ98/2] Routines1 könnte dies folgendermaßen aussehen:

    sqlj.install_jar('file:~/classes/Routines1.jar', 'routines1_jar')

    Der erste Parameter dieser Prozedur gibt das JAR File der zu installierenden Java Klasse und der zweite den SQL Namen der installierten Klasse an. Der SQL Name wird in der Folge für die Adressierung der Klasse verwendet.

    Zur Deinstallation bzw. zum Ersetzen der JAR Files werden die Prozeduren sqlj.remove_jar bzw. sqlj.replace_jar verwendet.

    Für das Beispiel nach [SQLJ98/2] Routines1 könnte dies folgendermaßen aussehen:

    // ersetzt das installierte jar file durch das angegebene neue file

    sqlj.replace_jar('file:~/classes/Routines1.jar', 'routines1_jar')

    // entfernt das installierte jar file

    sqlj.remove_jar('routines1_jar')

     

    Vergabe von SQL Namen für Funktionen und Prozeduren

     

    Nachdem eine Klasse installiert wurde, müssen die Methoden der Klasse dem DBMS bekannt gemacht werden. Dies geschieht, indem Namen für die Java Methoden definiert werden. Dafür werden die SQL Statements create procedure bzw. create function benutzt. Durch diesen Mechanismus ist es auch möglich mehrere verschiedene Namen für eine Java Methode zu definieren.

    Das Löschen des Namens ist mit Hilfe des SQL Statements drop möglich.

    Beispiel nach [SQLJ98/2] für die beiden Methoden region und correctState der Klasse Routines1:

    create procedure correct_states(old char(20), new char(20))

    modifies sql data

    external name 'routines1_jar:Routines1.correctState'

    language java parameter style java;

     

    create function region_of(state char(20)) return integer

    no sql

    external name 'routines1_jar:Routines1.region'

    language java parameter style java;

    Zuerst wird der SQL Name der Methode zusammen mit den Ein- und Ausgabeparametern übergeben. Dabei wird auch die Art und Weise der Ausgabeparameter spezifiziert (siehe 3.2.4 Verarbeitung von Ausgabeparametern und 3.2.5 Verarbeitung von Resultsets).

    Anschließend wird definiert, in wie weit die Java Methode Zugriff auf SQL Daten hat. Dazu werden die folgenden Klauseln verwendet:

    no sql: keinerlei SQL Operationen

    contains sql: SQL Operationen, aber kein lesen und modifizieren

    reads sql data: SQL Operationen, lesen, aber kein modifizieren

    modifies sql data: SQL Operationen, lesen und modifizieren

    Im Anschluß daran wird die Quelle der Methode durch Angabe der Namen von JAR Files, Klasse und Methode angegeben.

    Zum Schluß wird dann noch die Sprache der Methode spezifiziert (Java, SQLJ, ...).

     

    Überladen von Java Methoden und SQL Namen

     

    In SQLJ ist es möglich Prozeduren und Funktionen zu überladen und damit ein und den selben Namen mehrmals zu benutzen. Dies geschieht völlig unabhängig von Java. Damit überladene Prozeduren und Funktionen in SQL genutzt werden können, müssen einerseits die Java Methoden überladen werden und anderseits bei der Definition des Funktions- und Prozedurnamen dieser auch überladen werden.

    Beispiel nach [SQLJ98/2]:

    public class Over {

    public static boolean isOdd(Integer) {...};

    public static boolean isOdd(Float) {...};

    }

     

    create function odd(integer) return bit

    external name 'over_jar:Over.isOdd'

    language java parameter java;

     

    create funtion odd(real) return bit

    external name 'over_jar:Over.isOdd'

    language java parameter java;

     

    Verarbeitung von Ausgabeparameter

     

    Bei der Arbeit mit stored procedures werden oft Ausgabeparameter benötigt. SQL unterstützt diese, Java hingegen macht keinen Unterschied zwischen Ein- und Ausgabeparametern. Darum verwendet SQLJ Arrays als Ausgabeparameter. Diese Arrays beinhalten nur ein Element, den Rückgabewert. Bei der Verwendung dieser Prozeduren sind diese Arrays allerdings nicht sichtbar, sondern nur in der Java Methode. Beim Aufruf einer solchen Prozedur wird ein normaler skalarer Wert zurückgeliefert. Das Mapping zwischen Java Array und skalarem Datentyp geschieht hierbei implizit.

    Beispiel:

    public class Routines1 {

    public static void emp_age(int id, int[] age) throws SQLException {

    Connection con = DriverManager.getConnection("jdbc:default:connection");

    PreparedStatement stmt =

    con.prepareStatement("SELECT age FROM emp WHERE id = ?");

    stmt.setInteger(1, id);

    Result rs = stmt.executeQuery();

    rs.next();

    age[0] := rs.getInt("age");

    return;

    }

    }

     

    Verarbeitung von Resultsets

     

    Ein spezieller Fall des Ausgabeparameter sind Resultsets. SQL stored procedures können diese verwenden, darum muß es auch möglich sein, daß Java Methoden Resultsets als Ausgabeparameter benutzen können. Dazu wird in der Methode ein zusätzlicher Parameter eingeführt. Dieser Parameter ist ein Array der Klasse ResultSet oder einer Klasse, die vom SQLJ Iterator abgeleitet wurde. Durch diese Vorgehensweise ist es möglich, daß eine Java Methode mehrere Resultsets zurückliefern kann.

    Beispiel nach [SQLJ98/2]:

    public class Routines1 {

    public static void orderedEmps(int regionParm, ResultSet[] rs) throws SQLException {

    Connection con = DriverManager.getConnection("jdbc:default:connection");

    PreparedStatement stmt =

    con.prepareStatement("SELECT name, region_of(state) as region, sales

    FROM emp WHERE region_of(state) > ? and

    sales IS NOT NULL

    ORDER BY sales DESC");

    stmt.setInt(1, regionParm);

    rs[0] = stmt.executeQuery();

    return;

    }

    }

     

    Vergabe von SQL Zugriffsrechen

     

    Zugriffsrechte können für die installierten JAR Files, Prozeduren und Funktionen definiert werden. Dies wird durch die SQL Statements grant und revoke realisiert.

    Beispiel nach [SQLJ98/2]:

    // Benutzungsrecht für das jar file routines1_jar

    grant usage on routines1_jar to Smith

    // Ausführungsrecht für die Prozedur/Funktion correct_states

    grant execute on correct_states to Smith

     

    Fehlerbehandlung

     

    Bei der Fehlerbehandlung in SQLJ wird zwischen den SQLJ Prozeduren und den Java Methoden unterschieden.

    Fehler, die in einer Java Methode auftreten, können in der Methode durch Java Exceptions abgefangen werden. Wenn ein Fehler nicht abgefangen wird, so wird der String der Fehlermeldung (SQLException.toString()) an das DBMS zurückgegeben.

    Fehler, die bei der Verwendung von SQLJ Prozeduren entstehen, werden durch SQL Exceptions abgefangen. Dabei wird ein spezifischer SQLSTATE Code ausgegeben.

    SQLSTATE

    Condition Class Subcondition Subclass
    Java DLL 46 Invalid URL 001
    Java DLL 46 Invalid jar name 002
    Java DLL 46 Invalid jar deletion 003
    Java DLL 46 Invalid jar name 004
    Java DLL 46 Invalid replacement 005
    Java DLL 46 Invalid grantee 006
    Java DLL 46 Invalid signature 007
    Java DLL 46 Invalid methode specification 008
    Java DLL 46 Invalid REVOKE 009
    Java execution 46 Invalid null value 101
    Java execution 46 Invalid jar name in path 102
    Java execution 46 Unresolved class name 103
    Java execution 46 Too many result sets 104
    Uncaught Java exception 46 (no subclass) 200
    Uncaught Java exception 46 User-defined (see above) mmm
    User-defined (see above) nn User-defined (see above) mmm

     

    Deployment Descriptors

     

    Bei der Installation von Java Klassen in SQL sind ein oder mehrere create procedure/function Aufrufe notwendig. Analog sind ein oder mehrere drop Aufrufe notwendig, um die Java Klassen wieder zu entfernen. Um diesen Aufwand zu reduzieren wurde das Konzept des Deployment Descriptors eingeführt. Diese Deployment Descriptors befinden sich im JAR File. Sie beinhalten eine Anzahl von SQL Statements, die bei der Installation bzw. Deinstallation automatisch ausgeführt werden.

    Beispiel nach [SQLJ98/2]:

    SQLAction[] = {

    "BEGIN INSTALL

    create procedure correct_states(old char(20), new char(20))

    modifies sql

    external name 'thisjar:Routines1.correctStates'

    language java parameter style java;

    grant execute on correct_states to Baker;

    create function region_of(state char(20)) return integer

    no sql

    external name 'thisjar:Routines1.region'

    language java parameter style java;

    grant execution on region_of to public;

    END INSTALL"

    "BEGIN REMOVE

    revoke execute on correct_states from Baker;

    drop procedure correct_states restrict;

    revoke execution on region_of from public;

    drop function region_of;

    END REMOVE"

    }

     

    Verwendung von Java Klassen als SQL Prozeduren

     

    Wie bereits am Anfang dieses Kapitels ausgeführt lassen sich die Java Klassen nach der Installation verwenden, als ob es normale stored procedures wären. Für den Aufrufer der Methode ist nicht ersichtlich, daß es sich dabei um eine Java Methode handelt.

    Beispiel nach [SQLJ98/2]:

    SELECT name, region_of(state) as region

    FROM emps

    WHERE region_of(state) = 4

     

    SQLJ Teil 2: Java Klassen als SQL Datentypen

     

    Teil 2 von SQLJ beschäftigt sich damit, wie man Java Klassen als SQL Typen verwenden kann. Die Programmierung von Datenbankanwendungen mit Java wird damit deutlich erleichtert, da das Mapping von Java und SQL Datentypen entfällt.

    Voraussetzung für die Verwendung einer Java Klasse als SQL Datentyp ist, daß die Klasse das Interface von java.io.Serializable oder java.sql.SQLData implementiert.

    Damit eine Java Klasse als SQL Datentyp verwendet werden kann, muß diese zuerst installiert und anschließend daraus ein SQL Datentyp definiert wird. Die Installation der Java Klasse geschieht auf die gleiche Weise, wie in Kapitel 3.2.1 Installation von Java Klassen in SQL beschrieben ist. Natürlich ist es auch für SQL Datentypen möglich Zugriffsrechte zu vergeben. Dies ist in Kapitel 3.2.6 Vergabe von SQL Zugriffsrechten beschrieben.

    Beispiel nach [SQLJ98/3]:

    public class Adress implements java.io.Serializable {

    public String street;

    public String zip;

    public static int recommendedWidth = 25;

    public Adress() {

    street = "Unknown";

    zip = "None";

    }

    public Adress(String s, String z) {

    street = s;

    zip = z;

    }

    public String toString() {

    return "Street= " + street + " Zip= " + zip;

    }

    }

     

    Vergabe von SQL Namen für SQL Datentypen

     

    Nachdem das JAR File mit den Java Klassen erfolgreich installiert wurde müssen die Klassen noch als Datentypen registriert werden, damit sie in SQL benutzt werden können. Dies wird mit dem SQL Statement create type realisiert.

    Beispiel nach [SQLJ98/3]:

    create type addr external name 'Adress' language java

    (

    zip_part char(10) external name 'zip',

    street_part varchar(50) external name 'street',

    static method rec_width_part() return integer external variable name 'recommendedWidth',

    method another_addr() return addr external name 'Adress'

    method another_addr(s_parm varchar(50), z_parm char(10)) return addr external name 'Adress',

    method string_rep() return varchar(255) external name 'toString'

    )

    Als erstes wird der Name des neuen Datentyp und die Quelle zusammen mit der Sprache angegeben. Im Anschluß daran werden die gewünschten Variablen und Methoden mit ihren Schnittstellen und der Quelle beschrieben. Dabei müssen nicht zwangsläufig alle Variablen und Methoden verwendet werden.

    Interessant ist die Variable recommendedWidt, die in Java als statisch deklariert ist. Da SQLJ keine statischen Variablen kennt wird diese Variable in SQLJ als statische Methode rec_width_part benutzt.

     

    Verwendung von Java Klassen als SQL Datentypen

     

    Die Arbeit mit Java Klassen als SQL Datentypen funktioniert nicht ganz so, wie man das von den üblichen SQL Datentypen gewohnt ist. Die Benutzung dieser Datentypen lehnt sich stark an die Benutzung von Objekten in Java an. Wichtig ist, daß bei der Benutzung eines solchen Datentyps immer eine Instanz der Java Klasse erzeugt werden muß. Dies wird mit Hilfe des new Operators gemacht, der einen passenden Konstruktor der Java Klasse aufruft. Für den Zugriff auf Variablen und Methoden des Datentyps wird der Punkt Operator verwendet.

    Beispiel:

    INSERT INTO emps VALUES('Bob Smith',

    new addr(432 Elm Street', '95123'))

     

    SELECT name, home_addr.zip_attr

    FROM emps

    WHERE home_addr.street_attr = '456 Shoreline Drive'

     

    UPDATE emps

    SET home_addr.street_attr = '457 Shoreline Drive',

    home_addr.zip_attr = '99323',

    WHERE home_addr.to_String() like '%456%Shore%'

     

    Kollabierende Subklassen

     

    Bei der Verwendung von abgeleiteten Klassen in SQL kann es zu einigen Problemen kommen. Denkbar wäre, daß man einen Datentyp von der abgeleiteten Klasse erzeugt, ohne einen entsprechenden Datentyp der Superklasse zu besitzen. In diesem Fall ist es sogar möglich Variablen und Methoden der Superklasse für den Datentyp zu verwenden. Mit der Definition under im create procedure/function Statement lassen sich diese Probleme verhindern. Es sorgt dafür, daß nur die Variablen und Methoden der aktuellen Klasse verwendet werden können.

     

    Java Blend

     

    Java Blend ist ein Tool von Sun Microsystems Inc. Java Blend ermöglicht es zu Java Klassen das entsprechende Datenbankschema bzw. zu einem existierenden Datenbankschema die entsprechenden Java Klassen automatisch zu erzeugen.

    Bei den bisher erwähnten Methoden des Datenbankzugriffs war es nötig, daß der Entwickler sowohl Kenntnisse über die Programmiersprache Java, also auch Kenntnisse über SQL besitzen mußte. Sun versucht mit einer neuen Technologie namens Object/Relational Mapping dieses Problem zu lösen, indem der Entwickler sich gar nicht mehr um die Datenbank oder um SQL Statements kümmern muß. Der Entwickler schreibt die Java Anwendung und Java Blend setzt die Klassen anschließend in ein entsprechendes Datenbankschema um.

    Eine solche Umsetzung könnte im einfachsten Fall so aussehen:

    SQL Java
    CREATE TABE customer (

    custid INTEGER NOT NULL,

    adress VARCHAR(50),

    rep INTEGER,

    PRIMARY KEY (custid),

    FOREIGN KEY (rep)

    REFERENCES salesrep)

    Class Customer

    Implements Persistence Capable {

    Int custID;

    String adress;

    SalesRep rep;

    }

    Nach [SUN98/1]

    Java Blend bietet dabei folgende weitere Möglichkeiten:

     

    Zusammenfassung

     

    Mit der Entwicklung von JDBC im Jahre 1996 wurde für Java eine standardisierte Datenbank-API geschaffen. Die Integration von ODBC hat zu einer großen Akzeptanz der API in der Industrie geführt, da von Anfang an eine große Anzahl an DBMS unterstützt wurden. Damit wurde verhindert, daß verschiedene Hersteller eigene inkompatible Datenbank-APIs für Java schaffen. In der Zwischenzeit hat sich JDBC als Standard durchgesetzt.

    Die alternative Methode des Datenbankzugriffs ist keine konkurrierende API, sondern setzt auf JDBC auf. SQLJ bietet Entwicklern eine high-level API, die vergleichbar mit anderen APIs für C, C++ oder COBOL ist. Durch die Zusammensetzung des Konsortiums aus den wichtigsten Herstellern von Software und Datenbanksystemen ist eine große Akzeptanz von SQLJ zu erwarten. Mittlerweile gibt es auch bereits die ersten Implementationen, z.B. Oracle 8i, Sybase Adaptive Server Anywhere 6.0.

    Abschließend läßt sich sagen, daß Java eine hervorragende Basis für Datenbankanwendungen ist. Java bietet die Vorteile der Programmiersprache, wie Sicherheit, Stabilität und Robustheit und verbindet diese mit der Möglichkeit des einfachen und sicheren Datenbankzugriffs mittels JDBC. Weiterer Vorteil von Java ist die Portierbarkeit auf verschiedene Plattformen, was die Entwicklungszeit für Datenbanksoftware drastisch reduziert. Speziell für Firmen mit Intranet ist Java durch die Verwendung von Applets sehr interessant geworden. Dies alles wird dazu führen, daß in den nächsten Jahren vermehrt Datenbankanwendungen in Java geschrieben werden.

     

    Literaturverzeichnis

     

    JDBC - Datenbankzugriff mit Java, Addison-Wesley, 1998

    JDBC: A Java SQL API, 1997

    http://www.java.sun.com/products/jdbc

    SQLJ Part 0, now known as SQL/OLB (Object-Language Bindings), 1998

    http://www.acm.org/sigmod/record

    SQLJ: Java and Relational Databases, 1998

    http://www.sqlj.org

    Working Draft, 1998

    http://www.sqlj.org

    Working Draft, 1998

    http://www.sqlj.org

    http://www.sun.com/software/javablend/whitepaper/index.html