DB-Anwendungsprogrammierung - Universität Basel | Informatik

Werbung
Herbstsemester 2013
CS261 Web Data Management
Kapitel DB-6:
DB-Anwendungsprogrammierung
H. Schuldt
Möglichkeiten der DB-Anwendungsprogrammierung
SQL kann auf verschiedene Arten mit Programmiersprachen gekoppelt werden.
Diese Varianten führen zum Teil zu deutlichen Unterschieden in der
Anwendungsentwicklung
1. Erweiterung der Datenbanksprache um Programmierkonstrukte
(turing-vollständiges SQL). Diese Programme
werden in der Regel in der Datenbank definiert, gespeichert und
ausgeführt („stored procedures“).
2. Erweiterung der Programmiersprache um Datenbankkonstrukte:
Persistente Programmiersprachen (z.B. Pascal/R)
3. Einbettung der Datenbanksprache in die Programmiersprache:
"Embedded SQL" (ESQL). SQL-Anweisungen werden speziell
gekennzeichnet und von Precompiler in Bibliotheksaufrufe umgewandelt.
4. Verwendung von standardisierten Schnittstellen zur Datenbank:
(Call Level Interfaces). Vermeidung eines Precompilers (z.B. JDBC, ODBC)
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-2
1
Ebenen der DB-Anwendungsprogrammierung
•
Klassifikation der Anwendungsentwicklung mit Datenbanken
– Fat Server/Thin Client: Anwendungsentwicklung im DBMS
• Stored Procedures
• Trigger
– Fat Clients/Thin Server: Anwendungen laufen beim Client ab
• Embedded SQL
• SQL Call-Level-Interfaces
Client
…
Client
DBMS
DB
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-3
6.1 Erweiterung von DB-Sprachen
•
Thin Client / Fat Server-Architekturen
Client
ProzedurAufruf
Rückgabewerte
DBMS
Stored
Procedure
Trigger
UDT
HS 2013
Server
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-4
2
Fat Server
Anwendungslogik innerhalb der Datenbank
• Stored Procedures (TP-Lite)
– Verwendung einer 4GL (forth generation language)
• Turing-vollständiges SQL
– Speicherung und Ausführung in der Datenbank
– Standard unter SQL3 als “SQL/PSM” (= Persistent Stored Module).
Kommerzielle DBMS verwenden jedoch proprietäre Dialekte, z.B.
• PL/SQL in Oracle
• TransactSQL in Sybase und MS SQL Server
• Trigger
• Benutzerdefinierte Datentypen (User Defined Types, UDTs)
– Objektrelationale Erweiterung, Bestandteil von SQL-99
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-5
Stored Procedures: Übersicht
“Stored Procedure”
Internal
Procedure
External
Function
Procedure
Function
CREATE PROCEDURE credit (amount NUMBER, accountno INTEGER) IS
BEGIN
UPDATE account SET balance = balance + amount
WHERE account_number = accountno;
END debit;
Beispiel: Oracle PL/SQL
Einbindung von C-Funktionen
(Beispiel aus Oracle)
CREATE LIBRARY C_utils AS '/DLLs/utils.so';
CREATE FUNCTION debit (amount NUMBER, accountno INT) RETURN INT
AS LANGUAGE C LIBRARY C_utils NAME „debit_func";
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-6
3
Beispiel: Oracle-PL/SQL
•
Procedural Language extensions to SQL
– proprietäre 4GL-Sprache
– SQL erweitert um klassische Programmiersprachen-Konstrukte
– PL/SQL wurde erstmals 1991 in Oracle Version 6.0 von Oracle-DB-Servern
unterstützt
•
Dient (unter anderem) zur Entwicklung von Stored Procedures in Oracle
– Anwendungen, die in der DB gespeichert, verwaltet und auch dort
ausgeführt werden
•
Ab Version 8i: Java VM innerhalb der DB
– Java als Alternative zu PL/SQL möglich
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Oracle-PL/SQL:
Block Header
PL/SQL-Block
•
Header
– Name des Blocks
•
Declaration Section:
Angabe aller verwendeter
– Variablen
– Cursors
– Sub-Blöcke
•
Execution Section
– Programm-Code
•
Exception Section
– Ausnahmeverarbeitung bei
Fehlern
– Warnungen
IS
Declaration Section
BEGIN
Execution Section
EXCEPTION
Exception Section
END;
HS 2013
DB-6-7
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-8
4
Oracle-PL/SQL:
•
Header
Procedure, Function
PROCEDURE name ( parameter, parameter, ...)
IS
FUNCTION name ( parameter, parameter, ...)
RETURN type
IS
•
Parameter
– Variable Name, Direction, Type
Dummy1 IN NUMBER, Dummy2 OUT NUMBER
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Oracle-PL/SQL:
DB-6-9
Datentypen
•
Numerisch
– BINARY_INTEGER, INTEGER, SMALLINT, INT, POSITIVE, NATURAL
•
Zeichenketten
– CHAR, VARCHAR2, LONG
•
Binärdaten
– RAW, LONG RAW
•
Verschiedenes
– ROWID, BOOLEAN, DATE, NULL, CURSOR, TABLE
•
Verankerte Datentypen (Anchored)
– %TYPE, %ROWTYPE
•
Konvertierung zwischen Datentypen
– Implizit
– explizit über Konvertierungsfunktionen: TO_CHAR, TO_NUMBER, TO_DATE,
CHARTOROWID, CONVERT HEXTORAW, RAWTOHEX, ROWIDTOCHAR
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-10
5
Oracle-PL/SQL:
•
Declaration Section
Deklaration von Variablen, Cursors, Subtypen, Records, Tables
– variable_name NUMBER (2) [:= value];
– variable_name NUMBER (2) [DEFAULT value];
– variable_name schema.name%TYPE;
• Deklaration, ohne den genauen Datentyp zu kennen (automatische
Übernahme aus dem DB-Katalog)
• Prozedur ist von späteren Änderungen des Datentyps in der
entsprechenden Tabelle nicht betroffen
– TYPE type_name IS RECORD
( name1 typ1, name2 typ2, ...);
– TYPE type_name IS TABLE OF type;
– SUBTYPE subtype_typname IS base_type;
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Oracle-PL/SQL:
•
DB-6-11
Cursors
Eine Besonderheit von PL/SQL ist, dass immer nur einzelne Tupel zurückgegeben
werden können, aber keine Mengen
– Abhilfe: Cursor zur Iteration über eine Tupelmenge innerhalb der DB und zum
Auslesen einzelner Tupel
– Deklaration:
• CURSOR
• CURSOR
–
–
–
–
HS 2013
Öffnen:
Auslesen:
Schliessen:
Attribute:
c1 IS SELECT empno, ename, sal FROM emp;
c2 RETURN dept%ROWTYPE IS
SELECT * FROM dept WHERE deptno = 10;
OPEN c1;
FETCH c1 INTO my_empno, my_ename, my_sal;
CLOSE c1;
%ISOPEN, %FOUND, %NOTFOUND, %ROWCOUNT
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-12
6
Oracle-PL/SQL:
Wertübergabe
DECLARE
qty_on_hand
NUMBER(5);
new_order_id
NUMBER(5);
...
BEGIN
SELECT quantity INTO qty_on_hand FROM inventory
WHERE product_ID = 4711;
...
new_order_id := 42;
...
INSERT INTO ORDER(order_id, orderitem)
VALUES (new_order_id, this_orderitem);
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Oracle-PL/SQL:
Kontrollstrukturen
•
Verzweigungen:
IF – THEN - END IF;
IF – THEN – ELSE - END IF;
IF – THEN – ELSIF – THEN - ELSE - END IF;
•
Schleifen:
LOOP - EXIT WHEN - END LOOP;
FOR counter IN start ... end LOOP - END LOOP;
WHILE predicate LOOP - END LOOP;
HS 2013
DB-6-13
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-14
7
Oracle-PL/SQL:
Built-in Functions
•
Character Functions
ASCII, CHR, CONCAT, INITCAP, INSTR, LENGTH, LOWER, LPAD,
LTRIM, REPLACE, RPAD, RTRIM, SOUNDEX, SUBSTR, TRANSLATE,
UPPER
•
Date Functions
ADD_MONTHS, LAST_DAY, MONTHS_BETWEEN, NEW_TIME, NEXT_DAY,
ROUND, SYSDATE, TRUNC
•
Numeric Functions
ABS, ACOS, ASIN, ATAN, ATAN2, CEIL, COS, COSH, EXP(n),
FLOOR, LN(a), LOG(a,b), MOD(a,b), POWER(a,b), ROUND(a,b),
SIGN(a), SIN, SINH, SQRT, TAN, TAHH, TRUNC(a,b), DUMP,
GREATEST, LAST, NVL, SQLCODE, SQLERRM, UID, USER,
USERENV, VSIZE
•
Built-In Packages
DBMS_STANDARD, DBMS_ALERT, DBMS_DDL, DBMS_JOB, DBMS_LOCK,
DBMS_MAIL, DBMS_OUTPUT, DBMS_PIPE, DBMS_SESSION,
DBMS_SNAPSHOT, DBMS_SQL, DBMS_TRANSACTION, DBMS_UTILITY
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Oracle-PL/SQL:
•
DB-6-15
Exception Section
Exceptions bieten die Möglichkeit, auf vordefinierte Ausnahmen und auch auf
individuell deklarierte (und explizit anzustossende) Ausnahmen zu reagieren
DECLARE
my_exception EXCEPTION;
BEGIN
...
IF ... THEN RAISE my_exception;
...
EXCEPTION
WHEN ZERO_DIVIDE THEN
-- vordefinierte Ausnahme
INSERT INTO ... VALUES ...; COMMIT;
WHEN my_exception THEN Update ... SET ... ;
...
WHEN OTHERS THEN
-- Default-Fehlerbehandlung
ROLLBACK;
END;
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-16
8
Oracle-PL/SQL:
Packages
•
Logisch zusammengehörige Prozeduren/Funktionen, die in der Datenbank
gespeichert werden, lassen sich in Packages zusammenfassen
•
Eine Package besteht aus zwei Teilen:
– Spezifikation. Diese enthält
• globale Variablen
• Konstanten
• Interfaces der Funktionen und Prozeduren
– Body mit der
• Implementierung der Prozeduren bzw. Funktionen
HS 2013
Oracle-PL/SQL:
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Packages & Stored Procedures – Beispiel
CREATE PACKAGE emps AS
PROCEDURE hire (
empno INTEGER,
empname VARCHAR2(50))
END emps;
Spezifikation
CREATE PACKAGE BODY emps AS
PROCEDURE hire (
empno INTEGER,
empname VARCHAR2(50))
IS BEGIN
INSERT INTO employees VALUES
(empno, empname);
END hire;
END emps;
HS 2013
DB-6-17
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Implementierung
DB-6-18
9
Oracle-PL/SQL:
Zugriff auf Tabellen, Prozeduren, etc.
[schema_name.][pkg_name.]object_name [params]
•
•
Tabellen:
– Select * from konto;
– Select * from user.emp;
(Tabelle in eigenem Schema)
(Tabelle im Schema von Benutzer 'user')
Prozeduren:
– Aus SQL-Frontend (sqlplus)
• execute user.emps.hire(10, ‘Bill Gates’);
– Aus einer anderen Prozedur (execute nicht erforderlich)
• finance.banking.abheben (100, 5004);
•
Funktionen:
– Aus SQL-Frontend (sqlplus)
• Select user.emps.foo( 10, empno) from emp;
(Funktion foo wird für jedes Tupel von emp aufgerufen)
• Select finance.banking.gesamtsaldo(‘Ogi’) from Dual;
– Aus einer anderen Prozedur bzw. Funktion
• finance.banking.gesamtsaldo(‘Ogi’)
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-19
6.2 Einbettung der DB-Sprache in Programmiersprache
•
Fat Client / Thin Server: Embedded SQL
Embedded SQL
Anwendung
Call-Level SQL
Anwendung
SQL
Client
CLI Calls
Präcompiler
CLI-API (Application
Program Interface)
PräcompilerCall Level Interface
Runtime Library
Runtime Library
DBMS-Treiber
SQL-FAP (Format and Protocols),
herstellerdefiniert, z.B. Net8 von Oracle
DBMS
DB
HS 2013
Server
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-20
10
Embedded SQL (ESQL)
•
•
Nach ISO SQL-92 definierte Einbettung von SQL in Programmiersprachen
– z.B. Java (SQLJ), C, C++, Fortran, Pascal, Cobol, PL/1, Ada
Precompiler ersetzt die SQL-Aufrufe in Calls der jeweiligen Runtime Library des
verwendeten Datenbank-Servers
– Bei Wechsel der Datenbank müssen ESQL-Programme nur neu kompiliert
und gelinkt werden
•
Statisches ESQL
– Alle SQL-Statements müssen bereits zur Compile-Zeit vollständig bekannt sein
– Daher müssen auch alle verwendeten Datenbankobjekte zur Compile-Zeit
vorhanden sein
•
Dynamisches ESQL
– SQL-Statements werden erst zur Laufzeit erzeugt (dynamisches Generieren
von Strings, die SQL-Anweisungen beinhalten)
– Die verwendeten Datenbankobjekte müssen daher zur Compile-Zeit noch
nicht existieren
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-21
Embedded SQL: Standardarchitektur
•
Beispiel: Einbettung von SQL in ein C-Programm
ESQL/C-Quellprogramm
(z.B. Lieferung.pc)
DatenbankKatalog
ESQL-Precompiler
C-Quellprogramm
(z.B. Lieferung.c)
Zugriffsmodule/
Libraries
C-Compiler & Linker
Ausführbares Programm
(z.B. Lieferung)
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
Datenbank
DB-6-22
11
Kernprobleme bei der SQL-Einbettung
•
Die in Datenbanken verwendeten Datentypen (insbesondere Tupeltypen) sind
nicht immer identisch mit den Datentypen der verwendeten Programmiersprache
– Abhilfe: Abbildung von Tupeln bzw. Attributen der Datenbank (SQLDatentypen) auf die Datentypen der Programmiersprache und Möglichkeit der
Verwendung von Variablen der Programmiersprache (Wirtsprogrammvariable
bzw. Host Variables) in SQL-Anweisungen
•
SQL ist mengenorientiert. Das Ergebnis einer SQL-Anfrage ist eine Menge von
Tupeln, die in der Programmiersprache geeignet verarbeitet werden müssen
– Abhilfe: Möglichkeit zur Definition von Iteratoren (Schleifen) zur Verarbeitung
von Tupelmengen (Cursor-Konzept). Auslesen des Cursor-Inhalts in Host
Variablen zur weiteren Verarbeitung
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-23
Wirtsprogrammvariable (Host Variables)
• Die Attribute eines Resultattupels einer SQL-Anfrage werden an speziell deklarierte
Variable des Wirtsprogramms zugewiesen. Dazu ist eine Erweiterung des SQLStandards für die Einbettung in Programmiersprachen nötig
– Die INTO-Klausel gibt an, welche Host Variable mit dem Ergebnis einer SQLAnfrage belegt werden soll. Wirtsprogrammvariablen dienen daher als
„Übergabepuffer“ zwischen DBS und Programm.
– Beispiel:
EXEC SQL
SELECT PNr, Menge, Status INTO :pnr, :menge, :status
FROM Bestellungen WHERE BestNr = 555;
• Analog können SQL-Anweisungen mittels solcher Variable mit Eingabeparametern
versorgt werden.
– Beispiele:
EXEC SQL
SELECT PNr, Menge, Status INTO :pnr, :menge, :status
FROM Bestellungen WHERE BestNr = :bestnr;
INSERT INTO Bestellungen (BestNr,Monat,Tag,KNr,PNr, Menge)
VALUES (:bestnr, :monat, :tag, :knr, :pnr, :menge);
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-24
12
Beispiel: Embedded SQL – statisch
ESQL/CQuellProgramm
(SQL-Anweisungen
bekannt)
ESQL/C
Präcompiler
C-QuellProgramm
mit SQL
Anweisungen
und ESQL/C
Aufrufen
•
Beispiel:
credit (int accountno) {
EXEC SQL BEGIN DECLARE
SECTION;
NUMBER acc_no;
NUMBER bal;
•
EXEC SQL END DECLARE
SECTION;
acc_no := accountno;
EXEC SQL SELECT a.balance
INTO :bal
FROM account a
WHERE a.account_number =
:acc_no;
•
}
HS 2013
CPräprozessor
Compiler
und Linker
Ausführbares
Programm
Zur Compilezeit führt der Präcompiler u.a. folgende
Prüfungen durch (mit Hilfe von Informationen aus
dem Datenbank-Katalog):
– Existenz von Tabellen und Attributen
– Syntaxprüfung, Typenprüfung
Zusätzliche Ersetzungen:
– Die datenbankspezifischen Datentypen (Host
Variables) werden durch Datentypen der
jeweiligen Programmierumgebung ersetzt
– Beispiel (ESQL/C): VARCHAR2(10) wird zu
struct { unsigned short len;
unsigned char arr[10]; }
Ansatz ist recht unflexibel (da alle SQL-Statements
zur Compile-Zeit bekannt sein müssen), jedoch:
wenige Laufzeitfehler!
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-25
Indikatorvariable zum Erkennen von Nullwerten
•
Der Status einer SQL-Operation kann in den Wirtsprogrammen mit so genannten
Indikatorvariablen abgefragt werden. Beispiel:
EXEC SQL BEGIN DECLARE SECTION;
int
pnr;
int
vorrat;
short
vorrat_ind;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL SELECT Vorrat INTO :vorrat:vorrat_ind
FROM Produkte WHERE PNr = :pnr;
if (vorrat_ind == 0)
{ /* kein Nullwert */ ... }
else
{ /* Nullwert */ ... };
•
Allgemein können Indikatorvariable folgende Werte haben:
= 0 die entsprechende Wirtsprogrammvariable hat einen regulären Wert
= -1 die entsprechende Wirtsprogrammvariable hat einen Nullwert
> 0 die entsprechende Wirtsprogrammvariable enthält eine abgeschnittene
Zeichenkette
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-26
13
Beispiel eines ESQL/C-Programms …
• Programm: lieferung.pc – Variablendeklaration
/*** Programm zur Erfassung und Durchführung von Lieferungen bereits
bestellter Produkte***/
#include <stdio.h>
#include <string.h>
EXEC SQL INCLUDE SQLCA; /* Importieren der SQL Communication Area */
/* Innerhalb der SQL-Anweisungen ist Gross-/Kleinschreibung irrelevant. Sie dient hier nur zur Hervorhebung der SQL-Anweisungen */
/* Der Precompiler erzeugt an dieser Stelle die folgende
Datenstruktur:
struct sqlca {
char
sqlcaid[8];
long
sqlabc;
long
sqlcode;
struct {unsigned short sqlerrml; char sqlerrmc[70];} sqlerrm;
char
sqlerrp[8];
long
sqlerrd[6];
char
sqlwarn[8];
char
sqlext[8];
};
struct sqlca sqlca;
*/
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-27
… Beispiel eines ESQL/C-Programms …
main (){
/* Deklaration der Wirtsprogrammvariablen */
EXEC SQL BEGIN DECLARE SECTION;
/* Die hier deklarierten Wirtsprogrammvariablen unterliegen bei ihrer
Verwendung in SQL-Ausdrücken einer Typprüfung durch den Precompiler.
*/
int bestnr;
int pnr;
int menge;
VARCHAR status[10];
/* Der Precompiler erzeugt aus einer solchen Deklaration die folgende
Struktur (am Beispiel von status):
struct {unsigned short len; unsigned char arr[10];} status; */
VARCHAR user[20];
VARCHAR passwd[10];
EXEC SQL END DECLARE SECTION;
/* Globale Fehlerbehandlung */
EXEC SQL WHENEVER SQLERROR STOP;
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-28
14
… Beispiel eines ESQL/C-Programms …
•
Verbindungsaufbau mit dem Datenbanksystem und Beginn einer Transaktion
/* Verbindungsaufbau mit dem Datenbanksystem */
printf ("Benutzername?"); scanf ("%s", &(user.arr));
user.len = strlen(user.arr);
/* Konvertierung von C-String in VARCHAR */
printf ("Kennwort?"); scanf ("%s", &(passwd.arr));
passwd.len = strlen(passwd.arr);
/* Konvertierung von C-String in VARCHAR */
EXEC SQL CONNECT :user IDENTIFIED BY :passwd;
/* gleichzeitig Beginn einer Transaktion */
/* Dialogschleife */
printf ("Bitte geben Sie eine Bestellnummer ein. (0 = Programmende)\n");
scanf ("%d", &bestnr);
while (bestnr != 0)
{
EXEC SQL
SELECT PNr, Menge, Status
INTO :pnr, :menge, :status
FROM Bestellungen
WHERE BestNr = :bestnr;
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-29
… Beispiel eines ESQL/C-Programms …
if (sqlca.sqlcode == 0) /* Testen des SQL-Returncodes */
{
status.arr[status.len] = '\0';
/* Konvertierung von VARCHAR in C-String */
if (strcmp (status.arr, "neu") == 0)
{
EXEC SQL
UPDATE Produkte
SET Vorrat = Vorrat - :menge
WHERE PNr = :pnr AND Vorrat >= :menge;
if (sqlca.sqlcode == 0)
/* Testen des SQL-Returncodes */
{
strcpy (status.arr, "geliefert");
status.len = strlen (status.arr);
EXEC SQL
UPDATE Bestellungen
SET Status = :status
WHERE BestNr = :bestnr;
}
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-30
15
… Beispiel eines ESQL/C-Programms
•
Verbindungsabbau und Ende einer Transaktion
else
printf ("\n *** Ungenügender Lagervorrat ***\n");
}
else
printf ("\n *** Lieferung bereits erfolgt ***\n");
}
else
printf ("\n *** Bestellung nicht gefunden ***\n");
EXEC SQL COMMIT WORK;
/* Ende Transaktion und Beginn neue Transaktion */
printf ("Bitte geben Sie eine Bestellnummer ein.
(0 = Programmende)\n");
scanf ("%d", &bestnr);
}; /*while*/
exit (0); /* Verbindung mit dem DBS abbauen */
} /*main*/
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-31
Fehlerbehandlung in ESQL …
Fehler, die während der Abarbeitung von Embedded SQL-Programmen in der
Datenbank auftreten, können durch geeignete, automatisch generierte
Statusvariablen erkannt und dann auch behandelt werden.
1. Explizites Testen von sqlca.sqlcode im Wirtsprogramm nach einer SQLAnweisung:
= 0 Anweisung korrekt ausgeführt, keine besonderen Vorkommnisse
< 0 Fehler bei der Ausführung (siehe Fehlercodes im Manual)
> 0 Anweisung ausgeführt, Auftreten eines Sonderfalls,
z.B. signalisiert der Wert 1403, dass keine (weiteren) Treffertupel existieren
Zusatzinformation in den restlichen Komponenten von sqlca, z.B.:
sqlca.sqlerrd[2]
Anzahl der Tupel, die von einer
Insert-, Update- oder Delete-Anweisung
betroffen waren
sqlca.sqlerrm.sqlerrmc Fehlermeldung als Ascii-Text (max. 70 Zeichen)
sqlca.sqlerrm.sqlerrml Länge der Fehlermeldung
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-32
16
… Fehlerbehandlung in ESQL
2. Deklaration von "Exception-Handling"-Strategien:
EXEC SQL WHENEVER ( SQLERROR | NOT FOUND | SQLWARNING )
( STOP | GOTO label | CONTINUE )
wobei
SQLERROR einem SQLCODE < 0 entspricht,
NOT FOUND dem SQLCODE 1403 und
SQLWARNING einem SQLCODE > 0 (aber ungleich 1403).
– Der ESQL-Precompiler erzeugt automatisch nach jeder SQL-Anweisung einen
entsprechenden Vergleich mit sqlca.sqlcode, und zwar jeweils aufgrund
der textuell letzten WHENEVER-Anweisung vor der SQL-Anweisung.
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-33
Cursor-Konzept: Verarbeitung von Tupelmengen
•
Zweck eines Cursors ist die Verarbeitung von Tupelmengen in einer nichtmengenorientierten Wirtsprogrammiersprache. Ein Cursor ist also notwendig für
alle Anfragen mit mehr als einem Resultattupel.
– Beispiel: Ausgabe aller Bestellungen eines Kunden
...
printf ("Bitte geben Sie eine Kundennummer ein.
(0 = Programmende)\n");
scanf ("%d", &knr);
EXEC SQL DECLARE Kundeniterator CURSOR FOR
SELECT Monat, Tag, Bez, Menge
FROM Bestellungen WHERE KNr = :knr
ORDER BY Monat DESC, Tag DESC;
/* Cursor-Deklaration erfolgen immer
ohne INTO-Klausel */
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-34
17
Cursor-Konzept: Verarbeitung von Tupelmengen
EXEC SQL OPEN Kundeniterator;
/* An dieser Stelle werden die Eingabeparameter der SQLAnweisung (:knr) ausgewertet, und gedanklich wird hier die
Resultattupelmenge ermittelt*/
found = TRUE;
while (found) /* solange es noch Resultattupel gibt */
{
EXEC SQL FETCH Kundeniterator INTO :monat, :tag, :bez, :menge;
/* Hier werden die Wirtsprogrammvariable für die
Resultattupel festgelegt. */
bez.arr[bez.len] = '\0';
if ((sqlca.sqlcode >= 0) && (sqlca.sqlcode != 1403))
printf ("%d.%d.: %d %s", tag, monat, menge, bez);
else
found = FALSE;
}; /*while*/
EXEC SQL CLOSE Kundeniterator;
/* Freigabe des Cursors & der damit verbundenen DB-Ressourcen*/
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-35
Dynamisches ESQL
•
•
•
Ziel: Einbettung von SQL-Anweisungen, deren Struktur erst zur Laufzeit des
Wirtsprogramms bekannt ist.
Grobsyntax:
QSTR := AufbauQueryString(InputParams);
Execute QSTR;
Es wird als ein Programm (= SQL-Anweisung oder Folge davon) innerhalb des
laufenden Programms erzeugt und ausgeführt
Beispiele für Anwendungen, die dynamisches ESQL erfordern:
– SQL*Plus und ähnliche universelle, interaktive DBS-Schnittstellen sind
Programme, die dynamisches ESQL verwenden.
– Anwendungen, die sowohl Daten als auch Metadaten (Relationen des DBKatalogs) verarbeiten, benötigen in vielen Fällen dynamisches ESQL.
Solche Anwendungen sind mit dynamischem ESQL realisierbar, weil in
praktisch allen relationalen DBS der DB-Katalog in Form von Relationen
zugreifbar ist.
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-36
18
Beispiel: Embedded SQL – dynamisch
ESQL/CQuellProgramm
C-QuellProgramm
mit SQL
ESQL/C
Präcompiler
(SQL-Anweisungen
bekannt)
CPräprozessor
Compiler
und Linker
Anweisungen
und ESQL/C
Aufrufen
Ausführbares
Programm
Das SQL Statement ist erst zur Laufzeit
bekannt
– Der Precompiler kann weniger
char *table) {
Überprüfungen durchführen
char dyn_stmt[120];
– Mehr Flexibilität
sprintf(dyn_stmt,
"UPDATE %s SET balance = balance + – Aber auch mehr Laufzeitfehler
möglich!
:a WHERE account_number = :ano“,
table);
EXEC SQL PREPARE sql_stmt FROM
:dyn_stmt;
EXEC SQL EXECUTE sql_stmt USING
:amount, :accountno;
Beispiel:
credit( int amount, int accountno,
•
}
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-37
Erweiterungen der SQL-Syntax für Embedded SQL
DECLARE
cursor
OPEN
cursor
FETCH
cursor
CURSOR FOR
ordered_query
:
INTO
variable
,
CLOSE
cursor
table
DELETE FROM
CURRENT OF
WHERE
cursor
,
NULL
UPDATE
table
SET
column
=
expression
(
WHERE
HS 2013
Unordered_query
CURRENT OF
Web Data Management (CS261) – DB-Anwendungsprogrammierung
)
cursor
DB-6-38
19
6.3 Verwendung von standardisierten Schnittstellen
•
Fat Client / Thin Server: Call-Level SQL
Embedded SQL
Anwendung
Call-Level SQL
Anwendung
SQL
Client
CLI Calls
Präcompiler
CLI-API (Application
Program Interface)
PräcompilerCall Level Interface
Runtime Library
Runtime Library
DBMS-Treiber
SQL-FAP (Format and Protocols),
herstellerdefiniert, z.B. Net8 von Oracle
DBMS
DB
HS 2013
Server
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-39
SQL Call-Level Interface (CLI)
•
Call Level Interfaces sind standardisierte Schnittstellen zur Kommunikation mit
Datenbanken ohne Präcompiler
– CLI-API erlaubt das Erstellen und Ausführen von SQL-Anweisungen zur
Laufzeit (in ähnlicher Weise wie beim dynamischen embedded SQL)
•
SQL/CLI: Standard seit 1996
– Ursprung in Aktivitäten der SQL Access Group (SAG) mit dem Ziel, einen
vereinheitlichten Zugriff auf Datenbanken bereitzustellen
– Ist auch Bestandteil von SQL3
•
SQL/CLI beinhaltet
– DB-Verbindungsaufnahme und Beendigung
– Vorbereitung und Ausführen von SQL-Anweisungen (“prepare” und “execute”)
– Binden von Parametern an SQL-Anweisungen (“bind”)
– Entgegennahme von Resultaten
– Festlegung von Datentypen (über spezielle Codes für jeden Datentyp)
•
CLI-Call wird durch den proprietären DBMS-Treiber umgesetzt in herstellerspezifischen DB-Zugriff
– Mit geeignetem Treiber kann prinzipiell jede Datenquelle angesprochen
werden
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-40
20
CLI-Dialekte
•
•
Neben standardisiertem SQL/CLI haben sich noch weitere Dialekte herausgebildet
– ODBC (Open Database Connectivity): Microsofts CLI-Variante
• Beinhaltet die meisten (nicht alle) API-Calls des CLI-Standards
• Zusätzlich: spezielle Calls zur Unterstützung von Microsoft-Programmen
(Access, Excel, etc.)
– Proprietäre CLIs der DB-Hersteller (“Native API”)
• z.B. Oracle Call Interface (OCI)
In der Regel werden von einem Datenbanksystem mehrere CLI-Dialekte parallel
unterstützt
ODBC-API
SQL/CLI-API
Native API
Call Level Interface Runtime Library
DBMS-Treiber
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-41
Beispiel (CLI): SQL99 CLI
#include "sqlcli.h"
extern SQLHDBC hdbc;
extern SQLHENV henv;
/* Verbindung steht schon */
/* Umgebung */
void credit ( SQLHSTMT hstmt,
int amount, int accountno , char *table) {
/* hstmt wird von aussen gegeben, damit Transaktionskontrolle
ausserhalb dieser Prozedur. "credit" ist Baustein */
char update[120];
SQLINTEGER NameParamLength1;
SQLINTEGER NameParamLength2;
sprintf(update, "UPDATE %s SET balance = balance + ? WHERE
account_number = ? ", table);
SQLPrepare(hstmt, update, SQL_NTS);
SQLBindParameter(hstmt, 1, SQL_PARAM_MODE_IN, SQLCHAR, SQL_CHAR,
NAME_LENGTH, 0 &amount, NAME_LENGTH, &NameParamLength1);
SQLBindParameter(hstmt, 2, SQL_PARAM_MODE_IN, SQLCHAR, SQL_CHAR,
NAME_LENGTH, 0 &accountno, NAME_LENGTH, &NameParamLength2);
SQLExecute(hstmt);
}
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-42
21
Beispiel (CLI): Oracle-Dialekt (OCI)
#include “oci.h”
extern static OCIEnv *envhp;
void credit (OCIStmt *stmthp,
int amount, int accountno , char *table) {
char update[120];
static OCIBind *bnd1p = (OCIBind *) 0;
sprintf(update, “UPDATE %s SET balance = balance + :a
WHERE account_number = :ano “, table);
OCIStmtPrepare(stmthp, errhp, update, (ub4) strlen((char *update),
(ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));
OCIBindByName(stmthp, &bnd1p, errhp, (char *) ":A", -1,
(dvoid *) &amount, (sword) sizeof(accountid), SQLT_INT,
(dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0,OCI_DEFAULT);
OCIBindByName(stmthp, &bnd1p, errhp, (char *) ":ANO", -1, (dvoid *)
&accountno, (sword) sizeof(accountid), SQLT_INT, (dvoid *) 0,
(ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT);
OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (CONST
OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT);
}
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-43
Object CLI
•
•
Weiterentwicklung von CLI zu Objektschnittstellen
(SQL/CLI kennt nur prozedurale APIs)
– JDBC (Java Database Connection)
– ActiveX Data Objects (ADO)
Unterstützung von JDBC
– Entweder “direkt” durch Native-API
– Oder Umweg über JDBC-ODBC-Bridge
Java-Anwendung
JDBC-API
JDBC-Treiber-Manager
JDBC-ODBCBridge
SQL/CLI-API
JDBC-Native
Treiber
ODBC-API
Native API
Call Level Interface Runtime Library
DBMS-Treiber
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-44
22
JDBC
•
JDBC (Java Database Connectivity) besteht aus einer Menge von Java-Klassen
und Schnittstellen, die die Verwendung von SQL in Java-Programmen ermöglichen
– Java Package java.sql. Definiert Schnittstellen für das
•
•
•
•
Aufbauen von Verbindungen zur Datenbank
dynamische Erstellen von SQL Statements
Ausführen der Statements
Verarbeiten der Ergebnismengen
– Java Package javax.sql. Schnittstellen für server-seitige Verarbeitung
•
Aktuelle Informationen zu JDBC (Treiber, etc.) sind unter folgender URL zu
finden:
http://www.oracle.com/technetwork/java/javase/tech/indexjsp-136101.html
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-45
JDBC: Java Package java.sql
DriverManager
Connection
Statement
ResultSet
• java.sql.DriverManager: Möglichkeit zum Registrieren von Treibern
sowie zum Aufbau von Verbindungen zur Datenbank
• java.sql.Connection: Repräsentation einer Verbindung zur Datenbank
• java.sql.Statement: ermöglicht die Ausführung von SQL-Anweisungen
über eine gegebene Verbindung
• java.sql.ResultSet: verwaltet die Ergebnisse einer Anfrage in Form
einer Relation und unterstützt den Zugriff
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-46
23
JDBC: Beispiel …
Ablauf einer JDBC-Datenbankanwendung:
1. Aufbau einer Datenbankverbindung (inklusive Laden eines geeigneten Treibers)
2. Senden einer SQL-Anweisung
3. Verarbeiten der Anfrageergebnisse
4. Freigabe der Ressourcen
5. Fehlerbehandlung
import java.sql.*;
public class JdbcExample {
public static void main (String[] args) {
...
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-47
… JDBC: Beispiel …
Aufbau einer Datenbankverbindung
• Voraussetzung ist das Laden eines Treibers
– Explizit im Programm:
Class.forName ("oracle.jdbc.OracleDriver");
– Implizit durch Angabe in der Systemeigenschaft (Property) jdbc.drivers
Diese werden dann automatisch geladen
•
Verbindungsaufbau
– Methode getConnection() aus Klasse java.sql.DriverManager.
– Parameter sind URL der Datenbank (jdbc:<subprotocol>:<subname>),
UserID und Passwort.
• <subprotocol> enthält in der Regel der Name des Datenbanksystems
und des Treibertyps
• <subname> der Name der DB-Instanz
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-48
24
… JDBC: Beispiel …
...
String driverClass = "oracle.jdbc.OracleDriver";
try {
Class.forName (driverClass);
} catch (ClassNotFoundException exc) {
System.out.println (exc.getMessage());
System.exit(1);
}
try {
String url = "jdbc:oracle:oci:@mydb.com:1233/testdb";
Connection con =
DriverManager.getConnection(url, "user", "password");
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-49
… JDBC: Beispiel …
Senden einer SQL-Anweisung und Verarbeiten des Ergebnisses
• createStatement() bereitet ein SQL-Statement für eine existierende
Verbindung vor
• executeQuery(query) führt eine (dynamisch erzeugte) Anfrage query in
der Datenbank aus
•
Ergebnis ist eine Tupelmenge ResultSet
•
die Ergebnismenge der Anfrage wird mittels eines implizit vorhandenen Cursors
(dieser muss nicht wie bei embedded SQL explizit deklariert werden) verarbeitet
– Die Methode next() ermöglicht das Springen zum nächsten Tupel im
ResultSet
– next() liefert so lange true bis das Ende der Tupelmenge erreicht ist
– Für den Zugriff auf einzelne Attribute stehen geeignete get-Methoden zur
Verfügung (z.B. getString, getInt, etc.). Parameter dieser getMethoden im Cursor sind die Nummern der jeweiligen Attribute im Cursor
bzw. in der Anfrage (beginnend mit 1)
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-50
25
… JDBC: Beispiel …
...
String query = "SELECT Knr, name, saldo FROM Kunde";
Statement stmt = con.createStatement ();
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
int i = rs.getInt(1);
String s = rs.getString(2);
double d = rs.getDouble(3);
System.out.println(i + ", "
}
HS 2013
/* lese Kundennummer */
/* lese Name */
/* lese Saldo */
+ s + ", " + d + "CHF");
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-51
… JDBC: Beispiel …
Freigabe der Ressourcen
• Explizites Schliessen von ResultSet und Statement
•
Ist eigentlich optional (da diese Aufgabe auch der garbage collector übernehmen
kann); es ist jedoch empfehlenswert, die Ressourcen explizit freizugeben, da ein
Cursor evtl. auch viele Ressourcen des Datenbanksystems bindet.
...
rs.close();
stmt.close();
...
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-52
26
… JDBC: Beispiel …
Fehlerbehandlung
• Fehler werden als Ausnahme der Klasse SQLException signalisiert
• Details zu einem aufgetretenen Fehler können über die Methode getMessage()
entnommen werden
...
}
catch (SQLException sqlexc) {
System.out.println("SQLException: " +
sqlexc.getMessage());
}
}
}
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-53
… JDBC: Beispiel
•
In JDBC können neben SELECT … Anfragen auch andere SQL-Statements
ausgeführt werden (INSERT, UPDATE, DELETE) oder auch DDL-Statements
(CREATE TABLE, DROP TABLE, …)
•
•
Diese Operationen liefern keine Ergebnismengen zurück, benötigen also keinen
Cursor
Für diese Operationen steht die Methode execUpdate() zur Verfügung.
Rückgabewert ist die Anzahl der betroffenen Tupel (bei INSERT, UPDATE,
DELETE) bzw. 0 bei DDL-Statements.
•
Beispiel:
String update = "UPDATE Kunde SET Stadt = ‘Basel’
WHERE Knr > 4";
Statement stmt = con.createStatement ();
int rows = stmt.executeUpdate(update);
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-54
27
JDBC: PreparedStatement ...
•
•
•
Wenn in einem Java-Programm eine SQL-Anfrage mehrfach ausgeführt werden
soll (jedoch mit jeweils unterschiedlichen Parametern), dann ist es sehr
aufwändig, jedes Mal erneut den SQL-String im Java-Programm zu erstellen,
ihn an die Datenbank zu schicken, etc.
Die Schnittstelle PreparedStatement erlaubt es, eine Anfrage einmal
(vor der Ausführung) zum DBMS zu schicken. Dort wird das SQL Statement
kompiliert und damit zur Ausführung vorbereitet.
Die Eingabeparameter der PreparedStatements müssen mit ? gekennzeichnet
werden. Die Zuordnung von Werten zu vorher definierten Eingabeparametern
erfolgt über deren Position im PreparedStatement
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-55
… JDBC: PreparedStatement
•
Beispiel:
...
String prep = "INSERT INTO Kunde Values (?, ?, ?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement (prep);
pstmt.setInt(1, 4711);
pstmt.setString(2, 'Federer');
pstmt.setString(3, 'Lausanne');
pstmt.setDouble(4, 1500.20);
pstmt.setDouble(5, 0.15);
int i = pstmt.executeUpdate();
/*
/*
/*
/*
/*
Parameter
Parameter
Parameter
Parameter
Parameter
1:
2:
3:
4:
5:
Knr
Name
Stadt
Saldo
Rabatt
pstmt.setInt(1, 4712);
/* neue Belegung für
/* nächsten Aufruf
*/
*/
*/
*/
*/
*/
*/
...
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-56
28
JDBC: CallableStatement …
•
In JDBC lassen sich auch Fat Server-Konstrukte (Stored Procedures) in JavaProgrammen nutzen (Aufruf von Stored Procedures aus Java-Programmen heraus
– sofern die verwendete Datenbank Stored Procedures unterstützt)
•
Parameter werden im CallableStatement wieder mit dem Platzhalter ?
gekennzeichnet. Zusätzlich muss die „Richtung“ der Parameter angegeben
werden: IN, OUT oder INOUT
• CallableStatement ist von PreparedStatement abgeleitet. Daher stehen
alle Methoden zum Setzen der Parameter zur Verfügung (Angabe von
Positionsnummer innerhalb des Strings und Wert)
•
Bei OUT und INOUT-Parametern muss vor der Ausführung deren JDBC-Typ
festgelegt werden. Dies geschieht mit Hilfe der Methode
registerOutParameter
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-57
… JDBC: CallableStatement
•
Beispiel:
...
String call = "CALL deposit (?, ?, ?)";
/* erster Parameter: Kontonummer (IN)
zweiter Parameter: Einzahlungsbetrag (IN)
dritter Parameter: neuer Kontostand (OUT)
*/
CallableStatement cstmt = con.prepareCall (call);
cstmt.setInt(1, 13579);
/* Angabe Kontonummer */
cstmt.setDouble(2, 98.5);
/* Angabe Betrag
*/
cstmt.registerOutParameter(3, java.sql.Types.float);
cstmt.executeUpdate();
double kontostand = cstmt.getDouble(3);
...
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-58
29
Datentypen
•
SQL und Java besitzen jeweils eigene
Typsysteme
•
Bei der Abbildung zwischen SQL und
Java müssen auch die SQL-Datentypen
(JDBC-Datentypen) auf Java-Datentypen
abgebildet werden. Dies ist
insbesondere wichtig
– beim Zugriff auf Tupel-Attribute in
einem ResultSet mit Hilfe der
get...-Methoden
– bei der Übergabe von Parametern
an ein PreparedStatement mit
set...-Methoden
– beim Zugriff auf die OUT-Parameter
eines CallableStatement
HS 2013
JDBC-Typ
Java-Typ
CHAR
String
VARCHAR
String
NUMERIC
java.math.BigDecimal
DECIMAL
java.math.BigDecimal
SMALLINT
short
INTERGER
int
BIGINT
long
REAL
float
FLOAT
double
...
...
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-59
Zusammenfassung: Fat Server vs. Fat Client
•
Fat Client-Architekturen
• Traditioneller Ansatz in der zweistufigen Client/Server-Welt
+ Ausnutzen der Datenunabhängigkeit, die vom DB-Server
bereitgestellt wird
+ Standardisierte Schnittstellen
+ Gute Unterstützung eigener, individueller Anwendungen
+ Anwendungen lassen sich recht schnell entwickeln (z.B. mit Hilfe grafischer
Entwicklungswerkzeuge)
– Problem der Wartung, Software-Verteilung, etc. (Upgrades von
Anwendungen, die von vielen Clients verwendet werden, sind recht
aufwändig)
•
Fat Server-Architekturen
+ Einfachere Wartbarkeit (da zentrale Definition des Anwendungscodes)
+ Weniger Netzwerkbelastung (durch stärkeren Abstraktionsgrad der
bereitgestellten Prozeduren)
– Schlechte Unterstützung für individuelle, personalisierte Anwendungen
– Entwicklungsumgebungen sind in der Regel schlechter im Vergleich zu
Fat Client-Anwendungen
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-60
30
Ergänzende Literatur zu Kapitel 6
•
[Neu 92] K. Neumann: Kopplungsarten von Programmiersprachen und
Datenbanksprachen, Informatik-Spektrum Band 15, Heft 4, August 1992,
pp. 185-194
•
[SS 03]
G. Saake, K.-U. Sattler: Datenbanken und Java – JDBC, SQLJ, ODMG
und JDO. dpunkt.verlag, 2003.
HS 2013
Web Data Management (CS261) – DB-Anwendungsprogrammierung
DB-6-61
31
Herunterladen