ODBC/JDBC

Frank Gilsdorf, Universität Kaiserslautern

Einleitung

Datenbanken gewinnen gerade in heterogenen Umgebungen zunehmend an Bedeutung. Nachdem man sich von Mainframes immer mehr trennt, sind Datenbanken oft die einzige Möglichkeit, allen Benutzern eine gemeinsame Datenbasis zur Verfügung zu stellen. Meist greifen die Anwender gar nicht direkt auf die Datenbank zu, sondern sie benutzen Software, die Daten auf zentralen Datenbanken speichert. Als Beispiele sind hier SAP R/3 oder Netzwerkmanagement-Tools zu nennen. Ein weiterer wichtiger Punkt ist der Einsatz beim E-Commerce. Über Datenbanken können Versender ihr Warenangebot und ihren Warenbestand auch vom Kunden abfragen lassen.

Ein großes Problem beim Einsatz von Datenbanken ist deren Abfrage, da die Hersteller dafür proprietäre Schnittstellen benutzen. Die Datenbanken selbst laufen auf einem oder mehreren Servern. Die abfragenden Clients kommunizieren mit dem Server über ein proprietäres Protokoll. Wird die Datenbank gewechselt oder möchten sich die Clients mit einer Datenbank eines anderen Herstellers verbinden, müßte die Abfragesoftware geändert oder sogar neu geschrieben werden.

Um die Abfrage und Verwaltung der Datenbanken zu vereinheitlichen, wurde SQL (Structured Query Language) entwickelt. Hierbei handelt es sich um eine reine Abfragesprache ohne Kontrollkonstrukte wie Schleifen oder Verzweigungen. Deshalb können Programme nicht direkt in SQL programmiert werden. Programmiert wird mit Embedded-SQL. Hier werden die SQL-Befehle in ein Programm, das z. B. in C programmiert ist, eingebunden. Das C-Programm mit den eingebundenen SQL-Befehlen muß zuerst von einem Präprozessor bearbeitet werden, bevor der eigentliche Übersetzungsvorgang beginnen kann. Doch auch hier muß zumindest neu übersetzt werden, wenn die Datenbank gewechselt werden soll, da jeder Hersteller seinen eigenen Präprozessor einsetzt. Deshalb gestaltet sich das gleichzeitige Abfragen von verschiedenen Datenbanken sehr schwierig.

ODBC und JDBC sind APIs von Microsoft bzw. Javasoft, die Schnittstellen zur Verfügung stellen, um von höheren Programmiersprachen aus Datenbanken mittels SQL zu verwalten und abzufragen. Weiterhin bieten ODBC/JDBC die Möglichkeit, auch auf Datenbanken und andere Office-Produkte zuzugreifen, die keine SQL-Unterstützung haben. Der SQL-Befehlssatz wird in diesem Fall über einen Treiber implementiert. Auch das gleichzeitige Abfragen mehrerer Datenbanken aus einem Programm heraus, die dazu noch auf verschiedenen Servern liegen, ist kein Problem. Es muß gegebenenfalls nur ein weiterer Treiber auf dem Client installiert werden.

Im folgenden wird nun zuerst ein Überblick über SQL gegeben, das die Grundlage der Datenbankabfrage per ODBC oder JDBC darstellt. Danach wird ODBC und JDBC vorgestellt und dann die Vor- und Nachteile dieser beiden Schnittstellen abgewogen.

Datenbanken und SQL

Relationales Modell

Datenbank-Management-Systeme (DBMS) sind Programme, die Informationen so speichern, daß sie möglichst effizient abgefragt und modifiziert werden können. Die verbreitetste Art einer Datenbank ist das sogenannte relationale Datenbankmodell. Dieses basiert ausschließlich auf den mathematischen Grundlagen der relationalen Algebra. Das Grundelement einer relationalen Datenbank ist die Tabelle. Aus der Benutzersicht besteht jede relationale Datenbank nur aus Tabellen. Eine Tabelle setzt sich aus keiner, einer oder mehreren Zeilen und einer oder mehreren Spalten zusammen. Das Objekt, das genau einer Zeile und genau einer Spalte zugehört, heißt Datenwert. Das relationale Modell hat folgende wichtige Eigenschaften:

Die folgende Beispieldatenbank besteht aus zwei Tabellen. In Tabelle 1 sind die Mitarbeiter einer Firma gespeichert, in Tabelle 2 die Firmenwagen.

Mitarbeiter

Personal_Nr

Vorname

Nachname

Geburtsdatum

Auto_Nr

10001

Axel

Mayer

28.08.1943

5

10083

Anton

Sager

24.11.1954

null

10120

Jonas

Gans

01.01.1969

null

10005

Florian

Worms

04.07.1971

12

10099

Susanne

Mayer

21.09.1966

null

10035

Elisabeth

Schulz

24.12.1959

null

Firmenwagen

Auto_Nr

Hersteller

Modell

Baujahr

5

VW

Golf

1996

7

Ford

Escort

1998

12

Opel

Astra

1993

Wegen der großen Datenmengen und der Häufigkeit der Anfragen laufen solche Datenbanken oft auf dedizierten Servern und werden von Clients über ein Netzwerk abgefragt. Das Problem ist, eine Abfragemöglichkeit zu finden, die möglichst unabhängig von der Implementation der Datenbank selbst ist.

SQL Übersicht

SQL wurde als Sprache entwickelt, um relationale Datenbanken standardisiert abzufragen. Es gibt eine Basis von SQL-Befehlen, die von allen relationalen Datenbanken unterstützt wird. Die Amerikanische Normierungsbehörde ANSI hat SQL 1992 standardisiert. Diese Version heißt SQL-92. In der Literatur ist auch die Bezeichnung SQL2 zu finden. Da der komplette Sprachumfang, der auch SQL-92 full level" genannt wird, nicht von allen Datenbanken unterstützt wird, gibt es noch zwei Teilmengen dieses Standards:

SQL-Befehle: SELECT

Mit der SELECT-Anweisung werden Datenwerte aus einer Datenbank ausgewählt. Sie können aus einer oder aus mehreren miteinander verbundenen Tabellen ausgewählt werden. Das Ergebnis einer solchen Auswahl ist wiederum eine Tabelle. Als Argumente werden die Spalten angegeben, die in die Ergebnistabelle eingetragen werden. Die einfachste SELECT-Anweisung beinhaltet noch die FROM-Klausel, der eine oder mehrere Ausgangstabellen übergeben werden. Das Beispiel

SELECT Personal_Nr, Nachname FROM Mitarbeiter

liefert folgende Tabelle als Ergebnis:

Personal_Nr

Nachname

10001

Mayer

10083

Sager

10120

Gans

10005

Worms

10099

Mayer

10035

Schulz

Die einfachste Form der SELECT-Anweisung wird in der Praxis nicht so häufig benutzt, wie die folgende Form, in der eine oder mehrere Bedingungen existieren. Die Bedingungen werden mit Hilfe der WHERE-Klausel definiert, die die auszuwählenden Zeilen bestimmt. Die Auswahl

SELECT * FROM Mitarbeiter WHERE Nachname = 'Mayer'

ergibt folgende Tabelle:

Personal_Nr

Vorname

Nachname

Geburtsdatum

Auto_Nr

10001

Axel

Mayer

28.08.1943

5

10099

Susanne

Mayer

21.09.1966

null

Die Möglichkeit, zwei oder mehrere Tabellen einer Datenbank zu verknüpfen, ist eine der grundsätzlichen Eigenschaften des relationalen Datenmodells. Das Verknüpfen der Tabellen wird mit Hilfe des Operators Join durchgeführt, was im Allgemeinen bedeutet, daß Datenwerte aus mehreren Tabellen mittels einer SELECT-Anweisung ausgewählt werden. Auf die beiden Tabellen wird ähnlich einem Record in Pascal oder C mit einem ." zugegriffen:

SELECT Mitarbeiter.Vorname, Mitarbeiter.Nachname,
Firmenwagen.Hersteller, Firmenwagen.Modell
FROM Mitarbeiter, Firmenwagen
WHERE Mitarbeiter.Auto_Nr = Firmenwagen.Auto_Nr

Als Ergebnis wird folgende Tabelle geliefert:

Vorname

Nachname

Hersteller

Modell

Axel

Mayer

VW

Golf

Florian

Worms

Opel

Astra

Auf eine Gruppe von Datenwerten aus einer Spalte können sogenannte Aggregatfunktionen angewendet werden. Das Ergebnis jeder Aggregatfunktion ist immer ein einziger Wert. Es gibt fünf Aggregatfunktionen, die von allen Systemen unterstützt werden:

  • AVG berechnet das arithmetische Mittel der Datenwerte in einer Spalte. Die Spalte muß numerische Werte beinhalten, aber nicht unbedingt einen numerischen Datentyp haben.
  • MAX berechnet den größten und MIN den kleinsten Datenwert einer Spalte. Die Spalte kann numerische oder alphanumerische Datenwerte beinhalten.
  • SUM berechnet die Summe aller Datenwerte einer Spalte. Die Spalte muß numerische Werte beinhalten.
  • COUNT berechnet die Anzahl der Elemente innerhalb einer Spalte.

Die kleinste Personalnummer eines Mitarbeiters kann wie folgt ermittelt werden:

SELECT MIN (Personal_Nr) FROM Mitarbeiter
Weitere SQL-Befehle zur Datenmanipulation

Bisher wurde mit der SELECT-Anweisung nur die Auswahl von Datenwerten vorgestellt. Jetzt folgen noch die übrigen drei SQL-Anweisungen, die zur Datenmanipulation gehören. Sie lauten INSERT, UPDATE und DELETE.

Mit der einfachsten Form der INSERT-Anweisung werden explizit Zeilen in eine Tabelle eingefügt. In Tabelle 1 kann folgendermaßen ein weiterer Mitarbeiter eingefügt werden:

INSERT INTO Mitarbeiter VALUES
(10080, 'Horst', 'Müller', '13.02.1965', 13)

Wichtig ist, daß jeder eingefügte Datenwert denselben Datentyp wie die Spalte haben muß, in der er eingefügt wird.

Mit einer weiteren Form der INSERT-Anweisung werden die Zeilen einer existierenden Tabelle ausgewählt und in einer anderen Tabelle eingefügt. Auch hier müssen die Datentypen der einzelnen Spalten übereinstimmen.

INSERT INTO Mitarbeiter
SELECT * FROM Mitarbeiter_extern

Hier werden alle Zeilen der Tabelle Mitarbeiter_extern in die Tabelle Mitarbeiter eingefügt.

Die UPDATE-Anweisung ändert die Datenwerte von Zeilen einer Tabelle. Hierbei werden die Zeilen einer Tabelle auf Grund einer WHERE-Klausel zunächst ausgewählt. Danach werden aus diesen Zeilen mittels einer SET-Klausel die Spalten bestimmt, die geändert werden sollen. Mit einer UPDATE-Anweisung kann nur eine einzige Tabelle geändert werden:

UPDATE Mitarbeiter
SET Auto_Nr = 7
WHERE Personal_Nr = 10035

Mit der DELETE-Anweisung werden Zeilen aus einer Tabelle gelöscht. Die WHERE-Klausel liefert die Zeilen, die gelöscht werden sollen. Die explizite Angabe von Spalten ist nicht notwendig, da alle Datenwerte einer oder mehrerer Zeilen gelöscht werden.

DELETE FROM Mitarbeiter WHERE Personal_Nr = 10035
SQL-Befehle zu Tabellenmanipulation

Bisher wurden nur die Befehle zu Datenmanipulation erläutert. Nun folgen die notwendigen Befehle, die benötigt werden, um Tabellen aufzubauen und zu löschen.

Mit der SQL-Anweisung CREATE TABLE wird eine Tabelle mit allen dazugehörigen Spalten und deren Datentypen erzeugt. Es werden leere Tabellen erstellt. Um die Tabellen mit Inhalt zu füllen, muß der INSERT-Befehl benutzt werden. Das folgende Beispiel erzeugt Tabelle 2:

CREATE TABLE Firmenwagen
(Auto_Nr INTEGER, Hersteller CHAR(30),
Modell CHAR(30), Baujahr CHAR(4))

Die Änderung der Struktur einer Tabelle wird mit der Anweisung ALTER TABLE durchgeführt. Unter anderem können Spalten hinzugefügt oder gelöscht werden.

ALTER TABLE Mitarbeiter ADD (Wohnort CHAR(30))

Dieses Beispiel fügt der Tabelle Mitarbeiter eine Spalte Wohnort hinzu. Das nächste Beispiel löscht die Spalte Geburtsdatum:

ALTER TABLE Mitarbeiter DROP (Geburtsdatum)

Die Anweisung

DROP TABLE Mitarbeiter

löscht die komplette Tabelle Mitarbeiter inklusive Inhalt.

SQL Prozeduren

Eine stored procedure ist eine Gruppe von SQL-Befehlen, die mit einem Namen aufgerufen werden kann. Sie wird von der Datenbank kompiliert und abgespeichert und kann deshalb in Zukunft schneller aufgerufen werden, da sie direkt auf dem Datenbanksystem abläuft. Es folgt ein Beispiel einer einfachen Prozedur. Diese Prozedur übernimmt zwei Eingabeparameter, die Nummer des Autos (Car_No), das einem Mitarbeiter mit der Employee-Number (Emp_No) zugewiesen wird.

create procedure Assign_Car_Num (Car_No integer,
Emp_No integer)
as begin
UPDATE Mitarbeiter
SET Auto_Nr = Car_No
WHERE Personal_Nr = Emp_No
end

In SQL-92 ist noch nicht die Verwendung dieser stored procedures" definiert. Ende des Jahres 1998 wird die Version SQL3 erwartet, die dann neben diesen Prozeduren auch Mehrfachvererbung, benutzerdefinierte Datentypen und rekursive Abfragen normiert.

SQL Probleme

Es gibt grundsätzlich zwei Möglichkeiten, SQL-Anweisungen an eine Datenbank zu senden. Zum einen interaktiv über ein Verbindungsprogramm auf dem Client und zum anderen über ein Programm, das in einer Programmiersprache wie C oder COBOL mit eingebundenen SQL-Anweisungen geschrieben ist. Leider erfordern sowohl das Verbindungsprogramm als auch die eingebunden Anweisungen herstellerspezifische Lösungen. Mit dem Verbindungsprogramm eines Herstellers läßt sich kein Kontakt zum Server eines anderen Herstellers aufbauen. Die eingebundenen SQL-Anweisungen werden von einem Precompiler verarbeitet, bevor das eigentliche Übersetzen des Programms abläuft. Auch dieser Precompiler ist abhängig vom verwendeten Datenbanksystem. Aus diesem Grund ist auch die Abfrage verschiedener Datenbanksystemen gleichzeitig aus einem Programm heraus nicht möglich.

Ein weiteres Problem ist die Kommunikation zwischen Datenbank und Abfragesoftware. Auch hier benutzt jeder Datenbankhersteller sein eigenes Protokoll. Hier ist auch in naher Zukunft keine Besserung in Sicht, weil das Protokoll des SQL3-Standards normiert wird.

Aus diesen Gründen lassen sich in der Praxis nur sehr schwer portable Datenbank-Clients schreiben. Man braucht Möglichkeiten, sich mit Datenbanken zu verbinden, ohne vorher zu wissen, mit welchem Datenbanksystem man sich verbindet. Sowohl ODBC als auch JDBC haben die Möglichkeit, dies erst während der Laufzeit zu entscheiden.

ODBC

ODBC ist ein API von Microsoft für den Zugriff auf Daten in relationalen und nicht relationalen Datenbank-Management-Systemen. Mit Hilfe der ODBC-API können Applikationen auf Daten zugreifen, die in DBMS auf PCs oder Servern abgelegt sind, selbst wenn diese DBMSe andere Datenformate und andere Programmierschnittstellen verwenden [Geiger 1995]. ODBC könnte ein Akronym sein für Open Database Connectivity", laut Aussage von Microsoft ist es dies aber nicht, da sich Akronyme warenrechtlich nicht schützen lassen.

Die Unterstützung von ODBC ist nicht auf Microsoft beschränkt. Fast alle DBMS-Hersteller unterstützen ODBC, unter anderem Oracle, Informix, Novell, Borland, und IBM. ODBC ist eine Plattformübergreifende Lösung. Es existieren Portierungen für Apple Macintosh, zahlreiche Unix-Plattformen wie Sun Solaris oder IBM AIX und IBM OS/2. Diese Portierungen werden nicht von Microsoft erstellt, sondern von den Betriebssystemherstellern selbst übernommen.

ODBC stellt eine objektorientierte C++-Klassenbibliothek zur Verfügung. Es lassen sich aber auch andere Programmiersprachen wie z.B. Fortran oder Visual Basic benutzen. Durch die Benutzung dieses Basic-Dialektes ist auch der Zugriff auf Datenbanken von üblichen Office-Programmen wie Textverarbeitung oder Tabellenkalkulation möglich.

ODBC setzt zur Kommunikation mit dem Datenbanksystem SQL ein. SQL-Befehle werden in ODBC-Anweisungen eingepackt. ODBC interpretiert diese SQL-Befehle nicht. Es findet auch keine Syntaxkontrolle statt. Die SQL-Befehle werden auch nicht direkt zur Datenbank geschickt, sondern zuerst zu einem ODBC-Treiber. Dieser Treiber wird vom Hersteller der Datenbank zur Verfügung gestellt. Er nimmt die SQL-Befehle entgegen und sendet sie mit einem Herstellereigenen Protokoll zur Datenbank. Außerdem nimmt er Antworten der Datenbank entgegen und übergibt sie wieder an das ODBC-Programm.

Wegen des Treiberzugriffs gibt es auch keine Probleme beim Zugriff auf verschiedene Datenbanksysteme. Es muß gegebenenfalls ein neuer Treiber installiert werden. Welches Datenbanksystem benutzt wird, kann auch zur Laufzeit erst entschieden werden. Der Anwender kann über eine Dialogbox nach Datenbanksystem, Benutzername und Passwort gefragt werden. Die verschiedenen Treiber auf einem Client werden von einem Treiber-Manager verwaltet.

Treibermodelle

Es gibt grundsätzlich drei Möglichkeiten mit ODBC auf Datenbanken zuzugreifen: das One-Tier-, Two-Tier- oder Three-Tier-Modell. Die Modelle sind in der Grafik unten dargestellt

Beim One-Tier-Modell wird entweder auf eine lokale Datei oder auf eine lokale Datenbank zugegriffen. Beim Zugriff auf eine lokale Datei muß der ODBC-Treiber hier selbst die Informationen des Dateiaufbaus besitzen. Das One-Tier-Modell wird hauptsächlich bei der Kommunikation mit Office-Produkten benutzt, wenn z.B. die Textverarbeitung MS-Word sich Adressdaten von MS-Access für einen Serienbrief holt. Der Zugriff kann auch über eine ISAM-Engine erfolgen, um Dateien von z.B. der Tabellenkalkulation MS-Excel abzufragen. ISAM (Index Sequential Access Method) ist eine Zugriffsfunktion für eine einfache, sequentielle Datei auf der Festplatte, die einen Index oder mehrere Indizes einführt, um das Suchen und Sortieren von Spalten mit Daten zu vereinfachen. Üblicherweise unterstützt der One-Tier-Driver nicht den Mehrbenutzerzugriff, das heißt der Benutzer muß sich um die Konsistenz der Dateien bei gleichzeitigem Lese- und Schreibzugriff selbst kümmern. Da diese Treiber oft auch nur zur Kommunikation von Officeprogrammen benutzt werden, ist dies aber auch nicht nötig, da fast ausschließlich lesend zugegriffen wird.

Die Besonderheit beim Zugriff über das One-Tier-Modell ist, daß die lokale Datenbank oder die lokale Datei nicht über SQL angesprochen werden kann. Übliche Office-Software besitzt keinen SQL-Interpreter. Diese Funktionalität muß dann vom ODBC-Treiber nachgebildet werden.

Das Two-Tier-Modell entspricht den klassischen Client/Server-Systemen. Der Treiber auf der Client-Seite sendet und empfängt das Datenprotokoll der Datenbank, greift aber nicht direkt auf die Daten zu. Die Datenbank auf der Serverseite empfängt SQL-Anfragen vom ODBC-Treiber, führt diese aus und sendet das Ergebnis zurück.

Aus Sicht des Clients unterscheidet sich das Three-Tier-Modell kaum von dem Two-Tier-Modell. Hier ist einfach noch ein Server zwischen die Kommunikation von Datenbank und Client geschaltet. Dieser sorgt für die Verteilung auf verschiedene Datenbanken oder bietet den Clients eine einheitliche Zugriffsschnittstelle. So muß beim Einrichten einer neuen Datenbank nicht auf jedem Client ein neuer ODBC-Treiber installiert werden, sondern nur auf dem Server in der Mitte. Der Vorteil liegt in der leichteren Wartung auf Client-Seite, da diese nicht verändert werden müssen.

Konformitätsstufen

Um Interoperabilität zu gewährleisten, definiert ODBC zweierlei Konformitätsstufen: eine für Funktionsaufrufe (API-Konformität), und eine für die unterstützte SQL-Ebene (SQL-Konformität). Jeder Konformitätstyp hat drei Stufen.

Die API-Konformität wird verwendet, um die Menge der Funktionsaufrufe, die ein Treiber unterstützt in bestimmte Kategorien einzuteilen. Eine Anwendung fragt einen Treiber, welche Stufe er unterstützt, und verwendet dann genau die Funktionen aus dieser Konformitätsstufe. Ein Treiber muß also alle Funktionen der Stufe unterstützen, die er anzeigt. Er kann darüberhinaus auch noch Funktionen der nächsthöheren Stufe unterstützen. Um solchen Fällen gerecht zu werden, können Anwendungen mit SQLGetFunctions() einzelne Funktionen überprüfen. Die einzelnen Stufen sind folgendermaßen definiert:

Neben allen Kern-Funktionen umfaßt Stufe-1-Konformität von ODBC die folgenden Dinge:

  1. Erweiterte Funktionalität für die Verbindungsverwaltung, so daß eine Anwendung die vom Treiber bereitgestellte Schnittstelle verwenden kann, um eine Verbindung zur Datenquelle herzustellen.
  2. Funktionen zum Laden und Senden großer Datenwerte, sogenannte Blobs, von und zum Server. Der wichtigste Vorteil ist die Möglichkeit, einen einzelnen Wert für eine Spalte in einer Tabelle in Abschnitten zu laden oder zu senden, statt in einem einzigen Ausführungsschritt, wie es für die Kernstufe der Fall ist.
  3. Adaptive Programmierfunktionen ermöglichen es den Anwendungen, die Fähigkeiten des Treibers und des DBMS abzufragen.
  4. Die Funktion SQLGetTypeInfo() ermittelt alle Datentypen des Ziel-DBMS und ihre Abbildung auf die entsprechenden ODBC-Typen auf dem Client.
  5. Stufe 2: Stufe 2 enthält alle Funktionen, um eine umfassende und robuste API für den Datenzugriff zu schaffen. Neben den Funktionen aus Stufe 1 handelt es sich dabei unter anderem um die folgenden Dinge:
  6. Eine erweiterte Verwaltung für Verbindungen, wodurch es den Anwendungen möglich wird, dynamisch eigene Benutzeroberflächen für die Verarbeitung beliebiger Verbindungsszenarios zu schaffen.
  7. Zusätzliche Katalogfunktionen für die Rückgabe von Primär- und Fremdschlüsseln für Tabellen, Informationen, auf welche Tabellen und Spalten der Benutzer zugreifen darf, und Informationen über gespeicherte Prozeduren und die jeweiligen Argumente.

Es gibt ebenfalls drei SQL-Konformitätsstufen. Hierbei handelt es sich aber eher um Richtlinien, weniger um Einschränkungen. Es steht den Anwendern frei, beliebige SQL-Anweisungen an ein DBMS zu senden, auch wenn diese nicht in den SQL-Konformitätsstufen von ODBC enthalten sind. Die Treiber müssen alle SQL-Anweisungen für eine Konformitätsstufe unterstützen, wenn sie behaupten, dieser Stufe zu entsprechen. Diese kann mit der Funktion SQLGetInfo() ermittelt werden.

ODBC API-Konzepte

Eine ODBC-Applikation muß eine Reihe von Schritten durchführen, um sich mit einer Datenquelle zu verbinden und dort SQL-Statements abzusetzen. Diese Schritte werden im folgenden skizziert:

Mit SQLPrepare() wird eine Anweisung an den Server geschickt. Dort wird sie kompiliert und optimiert. Anschließend wird eine Referenz auf das kompilierte SQL zurückgegeben.

Beim Aufruf von SQLExecute() wird nur diese Referenz und gegebenenfalls Parameter an den Server übergeben. Dieser führt dann den kompilierten Code aus.

Eine Anwendung kann eine oder mehrere Zeilen ermitteln, indem sie das sogenannte Binden einsetzt. Das bedeutet, daß die Daten aus der Datenquelle den Variablen im Anwendungsprogramm zugeordnet werden. Mit SQLBindCol() wird einem SQL-Datenwert eine bestimmte Variable des Programmes zugewiesen.

SQLFetch() liest anschließend die Daten zeilenweise aus der Datenbank aus. Sie werden danach in die vorher gebundenen Variablen übergeben. Wenn mehr als eine Zeile erwartet wird, muß SQLFetch() entsprechend öfter aufgerufen werden. Die gebundenen Variablen werden bei jedem neuen Aufruf überschrieben.

Programmbeispiel

Um die Verwendung obiger Funktionen zu demonstrieren, wird noch folgendes Beispiel gegeben. Zuerst müssen die Verbindungs-Handles reserviert und die Verbindung aufgebaut werden:

SQLAllocEnv(..);

SQLAllocConnect(..);

SQLDriverConnect(..);

Jetzt wird ein Befehlshandle geholt und dieses mit einem SQL-Befehl belegt. Außerdem müssen vor dem Abschicken des Befehls noch die C-Variablen mit den Datentypen der Datenbank gebunden werden:

SQLAllocStmt(..);

wsprintf(szStmt, SELECT * FROM Sheet");

SQLPrepare(hStmt, szStmt, strlen(szStmt));

SQLBindCol(hStmt, 1, SQL_C_CHAR, (PTR)szName,...);

SQLBindCol(hStmt, 2, SQL_C_SLONG, (PTR)&nAge,...);

Jetzt wird der Befehl abgeschickt:

SQLExecute(hStmt);

Die Ausgabe kann jetzt vom Server abgeholt und in die Variablen des C++-Programms eingelesen. Da mehr als eine Zeile erwartet wird, muß das natürlich in einer Schleife geschehen:

for(i=1; (rc = SQLFetch(hStmt)) == SQL_SUCCESS; i++)

wsprintf(szResult, "Record #%d\Name: %s\nAge: %d",

i, szName, nAge);

Zum Abschluß muß jetzt noch der Speicher freigegeben und die Verbindung gelöscht werden:

if (hStmt) SQLFreeStmt(hStmt, SQL_CLOSE);

if (hDBC) SQLDisconnect(hDBC);

if (hDBC) SQLFreeConnect(hDBC);

if (hEnv) SQLFreeEnv(hEnv);

Wichtig ist, daß der ODBC-Treiber keine automatische Fehlerkontrolle übernimmt. Es muß also bei jedem ODBC-Befehl der Rückgabewert überprüft werden. Dies läßt sich am besten mit einem Makro lösen.

Zusammenfassung ODBC

Zusammenfassend läßt sich sagen, daß ODBC zur Zeit die am häufigsten benutzte Möglichkeit darstellt, Daten aus einer Datenbank abzufragen. Gerade im PC-Bereich benutzen viele Programme das One-Tier-Modell. Hier wird auf eine Version von MS-Access zugegriffen, die nur Daten entgegennimmt bzw. ausgibt, sich aber nicht über eine grafische Benutzeroberfläche einrichten läßt. Diese Version darf von jedem Entwickler kostenlos weitergegeben werden. Der Entwickler erstellt also eine Datenbank auf MS-Access-Basis und programmiert eine elegante Benutzerschnittstelle. So lassen sich zum Beispiel Lexika oder Telefonbuch-CDs erzeugen.

Eine weitere Anwendung ist natürlich die individuelle, firmeneigene Abfrage von Datenbanken. Die Kunden sind jetzt nicht mehr an einen bestimmten Hersteller gebunden. Sie können problemlos auf ihren Servern neue Datenbanksysteme, auch von anderen Herstellern, installieren. Es muß lediglich der ODBC-Treiber auf den Clients getauscht werden. Die Applikationen selbst müssen nicht geändert werden.

Übersicht JDBC

JDBC ist ein API von JavaSoft zum Absenden von SQL-Befehlen aus der Sprache Java heraus. Auch JDBC ist kein echtes Akronym für Java Database Connectivity. Es kann jede Datenbank angesprochen werden, für die ein JDBC-Driver existiert. Über die standardmäßig mitgelieferte JDBC-ODBC-Bridge kann darüberhinaus auch jede ODBC-Datenbank benutzt werden. Die JDBC-Treiber können von JavaSoft zertifiziert werden und erhalten dann das Siegel JDBC-Compliant. Dazu muß der Treiber mindestens SQL-92 Entry Level" verstehen. Aktuell erhältlich ist die Version 1.0. Ende des Jahres 1998 wird mit Erscheinen des JDK-1.2 auch JDBC Version 2.0 ausgeliefert. Da JDBC auf Java basiert, erbt es automatisch alle Vor- und Nachteile von Java. So zum Beispiel die hohe Portabilität, die Benutzung als Applet aus einem WWW-Browser heraus, aber auch die geringere Geschwindigkeit als ein C-Programm mit ODBC.

Treibermodelle

Java-Applikationen greifen über den JDBC Driver Manager" auf das Datenbanksystem zu. Der Manager wählt den passenden Treiber zur Datenbank aus. Grundsätzlich gibt es vier verschiedene Treiberarten, die in der Grafik unten dargestellt sind.

  1. JDBC-ODBC bridge plus ODBC driver: Dieser Treiber wird bei jeder Java-Umgebung ab JDK-1.1 mitgeliefert. Hier wird der Zugang zur Datenbank über einen bereits installierten ODBC-Treiber gewährt. Hierzu muß Binär-Code des ODBC-Treibers und u.U. des Datenbank-API auf den Client geladen werden.
  2. Native-API partly-Java driver: Dieser Treiber konvertiert JDBC-Aufrufe in Aufrufe des Datenbank-APIs einer speziellen Datenbank wie z.B. Oracle, Sybase o.ä. Auch hier muß der Binär-Code des API auf dem Client geladen werden.
  3. JDBC-Net pure Java driver: Dieser Treiber übersetzt JDBC-Aufrufe in ein datenbankunabhängiges JDBC-Net-Protokoll, welches dann später auf einem Server in das proprietäre Datenbankprotoll umgewandelt wird. Dieser Server hat die Möglichkeit beliebige Java-Clients an verschiedene Datenbanken anzuschließen.
  4. Native-protocol pure Java driver: Dieser Treiber wandelt JDBC-Aufrufe direkt in das proprietäre Datenbankprotokoll um. Er ist direkt in Java programmiert und benötigt keinen weiteren Binärcode. Da die Datenbankprotokolle nicht offengelegt sind, muß dieser Treiber vom Datenbankhersteller selbst erzeugt werden.

Nur die Treiber der Klassen 3 und 4 können auf beliebiger Hardware ausgeführt werden, da sie komplett in Java geschrieben sind. Wenn die Datenbank nur Treiber der Kategorie 1 oder 2 unterstützt, laufen die ODBC-Applikationen nur unter MS-Windows oder den verbreitetsten Unix-Systemen. Es gibt inzwischen für jede aktuelle Datenbank Treiber der Klassen 3 und 4. Eine aktuelle Liste findet sich unter http://www.javasoft.com/products/jdbc/jdbc.drivers.html.

JDBC nimmt üblicherweise über ein Two-Tier oder Three-Tier-Modell Verbindung mit der Datenbank auf (Grafik unten). Das One-Tier-Modell wird nur beim Zugriff über die JDBC-ODBC-Bridge benutzt. Hierbei gilt das bei ODBC schon Gesagte. Der Two-Tier-Zugriff wird bei Treibern der Klassen 2 und 4 benutzt. Der Three-Tier-Zugriff bei Treibern der Klasse 3.

JDBC API-Konzepte

Das Konzept von JDBC ist ähnlich dem des ODBCs. Auch hier sind nur rudimentäre Befehle vorhanden, die SQL-Statements an die Datenbank schicken. Eigentlich soll JDBC die Basis zur Entwicklung von High-Level-Tools sein. So ist z.B. ein Embedded-SQL for Java in Entwicklung. Hierbei handelt es sich um einen Precompiler der SQL-Befehle in einem Java-Programm direkt in JDBC-Aufrufe umwandelt.

Eine JDBC-Kommunikation unterteilt sich in die drei Schritte: Verbindungsaufbau, SQL-Befehle senden, das Verarbeiten der Antwort und Verbindungsabbau.

Beim Verbindungsaufbau muß zuerst der Treiber geladen werden:

import java.sql.*;

public class beispielJDBC {

public static void main(String args[]) {

Class.forName("jdbc.DriverXYZ");

Wenn der Treiber geladen wurde, kann die Verbindung aufgebaut werden. Dazu muß bekannt sein, welches Protokoll und Subprotokoll und welche Datenquelle benutzt werden. Diese werden in dem String url festgelegt. Protokoll und Subprotokoll entnimmt man der Dokumentation des JDBC-Treibers. So sieht ein Kontakt mit der JDBC-ODBC-Bridge auf die Datenquelle Fred folgendermaßen aus:

String url ="jdbc:odbc:Fred";

Connection con = DriverManager.getConnection(url,

"myLogin","myPassword");

Jetzt muß ein JDBC-Statement erzeugt werden. Das Statement kann dann mit executeQuery zur Datenbank geschickt werden, falls es sich um einen Abfrage-Befehl handelt. SQL-Befehle, die die Tabelle verändern oder Daten erzeugen, werden mit executeUpdate gesendet.

Statement stmt = con.createStatement();

Result rs = stmt.executeQuery("SELECT a, b, c FROM Table1");

Die Ergebnisse wurden jetzt automatisch in rs abgelegt. Sie können mit einer while-Schleife abgeholt werden:

while (rs.next()) {

int x = getInt("a");

String s = getString("b");

float f = getFloat("c");

}

Jetzt muß die Verbindung nur noch geschlossen werden:

stmt.close();

con.close();

}

}

Zusammenfassung JDBC

Die Verbreitung von JDBC ist wesentlich geringer als die von ODBC. Das liegt zum einen daran, daß JDBC noch in den Kinderschuhen steckt und von den Datenbankentwicklern noch nicht angenommen wurde. Zum anderen aber auch daran, daß es nur auf Java als Programmiersprache beschränkt ist. Da es noch relativ wenig kommerzielle Applikationen auf Java-Basis gibt sind auch JDBC-Programme entsprechend wenig vertreten. Trotzdem macht JDBC Sinn, da es die einzige Möglichkeit darstellt, mit Java auf Datenbanken zuzugreifen. Microsoft ist nicht bereit ODBC nach Java zu portieren und Sun hat sich entschlossen JDBC zu entwickeln. ODBC läßt sich nur über den Umweg über die JDBC-ODBC-Bridge benutzen. Sun möchte mit JDBC Microsofts ODBC nicht ablösen, sondern nur Java in diesem Punkt stärken, da bis zur Entwicklung von JDBC keine Möglichkeit bestand, auf Datenbanken zuzugreifen.

Vergleich ODBC/JDBC

Der Vorteil von ODBC liegt in der guten MS-Windows-Einbindung. So lassen sich die Treiber sehr elegant über Dialogboxen installieren und konfigurieren. Daraus ergibt sich allerdings auch der Nachteil, daß ODBC praktisch nur für MS-Windows verfügbar ist, abgesehen von einigen Unix-Systemen wie Solaris. Außerdem gibt es für jede Datenbank einen nativen Treiber. Dieser läuft aber in den meisten Fällen nur unter MS-Windows. Ein weiterer Vorteil ist die Skriptfähigkeit über Visual-Basic und damit auch die Kommunikation mit den üblichen Office-Produkte wie MS-Word oder MS-Excel.

JDBC verfolgt hier einen anderen Ansatz. Die Programmierung ist zwar der von ODBC ähnlich, und wer schon einmal mit ODBC gearbeitet hat, kann leicht auf JDBC umsteigen, das Treiberkonzept ist allerdings völlig anders. Da die Treiber im Idealfall in Java programmiert sind, kann ein JDBC-Programm auf jeder beliebigen Plattform laufen, die Java unterstützt. Der Datenbankhersteller muß seine Treiber natürlich auch nicht an die Hardware anpassen. Da JDBC nur mit Java zusammenarbeitet, ist die Einbindung in diese Sprache wesentlich harmonischer als ODBC in C++. Dies fällt vor allem bei der Fehlerbehandlung auf, die bei ODBC sehr umständlich von Hand gelöst werden muß.

Die Zukunft wird zeigen, ob die Datenbankhersteller bereit sind neben dem ODBC-Treiber auch noch einen für JDBC zu entwickeln. Microsoft arbeitet eng mit den Herstellern der Datenbanken zusammen, damit alle Änderungen am ODBC-Standard schnell in die Treiber einfließen können.

Der große Vorteil von JDBC liegt in der Sprache Java. Es lassen sich so leicht Applets erstellen, und man kann auf eine Datenbank von außen über eine WWW-Seite zugreifen. Das ist gerade im ständig wachsenden Markt für E-Commerce sehr wichtig. Damit lassen sich sehr einfach WWW-Seiten zum Electronic Shopping" erstellen.

Middleware

Als Middleware" bezeichnet man innerhalb eines Schichtenmodells eine Softwareschicht zwischen Betriebssystem und Applikationsebene. Middleware ist aus Applikationssicht eine Dienstleistungsschicht, die anstelle der Betriebssystemschnittstelle verwendet wird. Dies macht Sinn, wenn die angebotenen Dienste mächtiger sind und/oder die Schnittstelle Plattformunabhängigkeit gewährleistet. Im Fall von ODBC/JDBC liegt die Schicht zwischen Applikation und Datenbank. Bei beiden Produkten ist die Plattformunabhängigkeit aber gewährleistet, da sich die Datenbank ohne Änderung an der Applikation oder Neucompilieren austauschen läßt. Es muß lediglich der richtige Treiber installiert sein. JDBC geht das Middlewarekonzept noch weiter, da die Plattformunabhängigkeit sich auch auf die Applikation direkt bezieht. Dies gilt allerdings nur für Treiber der Klassen 3 oder 4.

In den Standardwerken zu ODBC [Geiger 1997] und JDBC [Hamilton et al. 1997] taucht das Wort Middleware" jeweils nur ein einziges Mal auf. Das liegt wohl daran, daß sich diese Bücher hauptsächlich an die Programmierer wenden, die das Stichwort Middleware nicht oder wenig interessiert.

Fazit

Zusammenfassend läßt sich sagen, daß ODBC/JDBC zur Zeit die einzige Möglichkeit darstellen von Client-Seite komfortabel auf Datenbanken zuzugreifen. SQL alleine kann nicht überzeugen, da es noch zu stark vom Datenbanksystem abhängig ist. Gerade die Einbindung in höhere Programmiersprachen über Embedded-SQL ist sehr umständlich gelöst. ODBC/JDBC benutzen zur Kommunikation zwar auch SQL, durch die Einbindung in normale Funktionen überläßt man die Konvertierung und Kommuniaktion aber einem Treiber. Dieser Treiber läßt sich auch von nicht besonders qualifiziertem Endanwendern einfach installieren.

Literatur

[Petkovic 1990]

Dusan Petkovic: SQL-die Datenbanksprache, McGraw-Hill

[Geiger 1997]

Kyle Geiger: Inside ODBC, Microsoft-Press

[Microsoft]

http://www.microsoft.com, ODBC-API

[Hamilton et al. 1997]

Graham Hamilton, Rick Cattel, Maydene Fischer: JDBC Database Access with Java, Addison-Wesley, Reading, Massachusetts

[JavaSoft]

http://www.javasoft.com, JDBC-API

Go to Main Go to Previous Go to Next