Anwendungsprogrammierung

Werbung
Anwendungsprogrammierung
5. Anwendungsprogrammierung
Anwendungen werden typischerweise in imperativen Sprachen entwickelt (C, Cobol,
Fortran, Java, C++…)
–
viel Funktionalität bei der “gewöhnlichen” Programmierung
–
sehr schwierig für Datenbankprogrammierung
–
flexibles Datenmodell:
basiert auf der Verarbeitung von einzelnen Datensätzen
Datenbankanfragesprachen (SQL) sind deskriptiv
–
wenig Funktionalität für die “alltägliche” Programmierung:
Eine einfache Aufgabe wie “Berechne den Flächeninhalt eines beliebigen Polygons”
ist in SQL nicht möglich.
–
sehr komfortabel für die Datenbankprogrammierung
–
restriktives Datenmodell:
basiert auf der Verarbeitung von Mengen (Relationen)
Anwendungsprogrammierung
Kopplungsmöglichkeiten
Evolutionäre Ansätze:
CALL-Schnittstelle
– Bereitstellung von Bibliotheken
Einbettung mit Vorübersetzer
– statisch: Struktur der SQL-Befehle ist bereits vorgegeben
– dynamisch: beliebige SQL-Befehle
Spracherweiterungen
– von SQL
– von einer imperativen Programmiersprache (z. B. PASCAL)
Skriptsprachen
– BASIC-ähnliche Sprachen ohne Typkonzept
– einfache Anbindung an Window- und Graphikumgebung
Frage:
Wie kann die Programmierung von Datenbankaufgaben mit der von “gewöhnlichen”
Aufgaben verbunden werden (ohne dabei die Vorteile von SQL aufzugeben)?
Seite 128 von 159
Seite 129 von 159
Anwendungsprogrammierung
5.1 Prozedurale CALL-Schnittstelle
basiert auf der Verwendung einer Bibliothek
–
im Fall von Oracle: Oracle Call Interface (OCI)
Quelldateien
Host-Compiler
gemeinsam vom AWP und dem Datenbank-Server genutzte Datenstrukturen
– zum Aufbau der Kommunikation
– zur Bearbeitung einer Anfrage
Cursor: im AWP benutzte Datenstruktur zum Zugriff auf Relationen der DB.
im AWP: Speicherung der SQL-Anfragen in einem String.
Typüberprüfung: nur im AWP möglich
Binden der Variablen aus dem AWP an die Datenstrukturen des DBMS-Server
Table 1:
DBMS-Bibliothek
Ablauf eines AWP:
Host-Linker
AWP
Anwendungsprogrammierung
Komponenten der CALL-Schnittstelle
Aufbau der Verbindung
zum DBMS-Server
DBMS-Server
Initialisieren
eines Cursors
Datenbank
Parsen eines
SQL-Statements
Binden von Eingabevariablen Schließen des
an das SQL-Statement
Cursors
Ausführen eines
Updates/Anfrage
Seite 130 von 159
Abkoppeln
vom Server
Seite 131 von 159
Anwendungsprogrammierung
Abfragen der
Ausgabeparameter
Anwendungsprogrammierung
JDBC - eine Call-Schnittstelle in Java
Ausführen einer Anfrage (im Detail):
Binden der Ausgabe
an Variablen des AWP
Setzen des
Cursors
Abbrechen der
Anfrage
Nachteil bei der Benutzung der CALL-Schnittstelle:
komplizierte Programmierung
fehleranfällig
Vorteile
hohe Flexibilität
Datenbankprogrammierung in Java unter Benutzung von SQL
– Anfragen werden als uninterpretierte Zeichenketten an das DBMS gegeben
– Resultate werden über Objekte einer Klasse ResultSet vom DBMS an das AWP
geschickt.
Client-Server Konzept
– DBMS läuft auf einem anderen Rechner als das AWP
Einheitliche Schnittstelle für verschiedene DBMS
Verwendung von strenger Typisierung (wenn immer möglich)
Unterstützung wichtiger Konzepte
– statische Anfragen
– parameterisierbare SQL Anfragen
– Unterstützung großer Objekte
– dynamische Anfragen und Metadaten
Seite 132 von 159
Seite 133 von 159
Anwendungsprogrammierung
Client/Server Kopplung in JDBC
Anwendungsprogrammierung
ODBC Kopplung
Client
Native Kopplung
JDBC
Client
JDBC
Server
Server
DBMS
ODBC
ODBC +
Datenbanktreiber
DBMS
DBMS-Net
Spezielle Netzsoftware des DBMS wird auf dem Client installiert. Methoden in JDBC
basieren auf den Funktionen der darunterliegenden Netzsoftware.
ODBC und entsprechende Datenbanktreiber sind auf dem Client installiert. Methoden
von JDBC basieren auf der Funktionalität von ODBC.
Vorteil
Unabhängigkeit von speziellen Datenbanksystemen
Nachteile
Nachteil
Installation der Netzsoftware auf allen Clients
keine Unabhängigkeit vom Datenbanksystem
Installation von ODBC + Datenbanktreiber auf allen Clients
Overhead von ODBC
Seite 134 von 159
Seite 135 von 159
Anwendungsprogrammierung
Native Pure Java Client
Anwendungsprogrammierung
Native-Protocol Pure Java Clients
Client
Server
Client
DBMS
DBMS-Net
JDBC
DBMS-Net
JDBC +
Datenbanktreiber
Server
DBMS
JDBC
Download
Ähnlich zur ersten Lösung, aber die Netzsoftware ist in Java reimplementiert, die nach
Bedarf vom Server geladen wird (siehe z. B. die derzeitige Anbindung an Oracle)
Vorteil
Ein spezielles in Java implementierte Netzwerkverbindung übermittelt die Anforderungen des Clients an einen Server. Beim Server wird dann die Anforderung an das DBMS
weitergereicht.
Vorteile
Keine Installation von spezieller Software am Client
Datenbankunabhängigkeit
keine Software auf dem Client
Nachteil
Abhängigkeit vom Datenbankhersteller
Seite 136 von 159
Seite 137 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
Wichtige Klassen bei JDBC
ResultSet
executeQuery
getMoreResults
exe
cut
eQu
ery
X
tXX
se
IS-A
Connection
t
n
e
m
tate
getConnection
pareS
pre
getXXX
ll
Ca
re
pa
IS-A
pre
Datentypen
Erzeugung eines Connection Objekts
Connection con = DriverManager.getConnection ("jdbc:oracle:thin:@venus.mathematik.uni-marburg.de:1521:Init_DB", "scott", "tiger");
createStatement
Statement
PreparedStatement
getXXX
Aufbau einer Verbindung
DriverManager
– Erste Zeichenkette entspricht einer URL zur Datenbank
– Zweite Zeichenkette ist der Benutzername
– Dritte Zeichenkette ist das Paßwort
Bevor das Connection Objekt erzeugt wurde, muß noch die entsprechende Treiberklasse
angemeldet werden.
Class.forName("oracle.jdbc.driver.OracleDriver") ;
CallableStatement
Die Namen in den Rechtecken entsprechen den Namen der verfügbaren Schnittstellen
Die gerichteten Kanten zeigen i. A. wie man ein Objekt einer Klasse (auf die eine Kante
gerichtet ist) mit Hilfe der anderen Klasse erzeugt.
Seite 138 von 159
Seite 139 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
Interpretierte Anfragen
Vorübersetzte Anfragen
SQL-Anfrage wird interpretiert (übersetzt und gleichzeitig ausgeführt). Das Ergebnis der
Anfrage wird einem Objekt der Klasse ResultSet übergeben. Eine nochmalige
Ausführung der Anfrage erfordert erneut eine Interpretation. Die Anfrage selbst ist nicht
parameterisierbar.
Statement stmt = con.createStatement();
Bei diesen Anfragen trennt man die Übersetzung der SQL-Anfrage von der Ausführung
der Anfrage.
PreparedStatement stmt = con.prepareStatement(“select x, y from Points where x < ? and
x > ?”);
// Die SQL-Anfrage wird übersetzt. Die Anfrage selbst besitzt zwei Parameter.
stmt.setInt(1, 20);
// Erzeugung eines neuen Objekts der Klasse Statement
ResultSet rs = stmt.executeQuery(“select count(*) from user_tables”);
stmt.setInt(2, 10);
// Übersetzen der Anfrage und Erzeugen eines neuen Objekts der Klasse ResultSet
rs.next();
// Die Parameter der Anfrage werden gesetzt.
ResultSet rs = stmt.executeQuery();
// durch die Operation next wird die Funktionalität eines Iterators bereit gestellt
System.out.println(“Anzahl der Tabellen: “ + rs.getInt(1));
// Zugriff auf die Datenfelder mit get-Funktionen
// Die Anfrage wird ausgeführt.
Vorteil
Werden Anfragen in ähnlicher Form mehrmals ausgeführt, erspart man sich hier die Zeit
für das mehrmalige Übersetzen.
Hoher Optimierungsaufwand lohnt sich beim Übersetzen
Seite 140 von 159
Seite 141 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
Prozedurale Anfragen
Dynamisches SQL
Fast alle DBMS unterstützen die Möglichkeit Prozeduren zu schreiben, in denen eine
Prozedur über Ein- und Ausgabeparameter verfügt. Wir werden in einem späteren Kapitel
darauf kurz eingehen.
JDBC erlaubt es, Anfragen dynamisch zu formulieren, da als Eingabe zur Ausführung
eines SQL-Befehls ein beliebiges Objekt der Klasse String erwartet wird.
String str;
…
ResultSet rs = con.createStatement().executeQuery(str);
Als Problem erweist sich hier aber, daß zur Laufzeit des Programms der Typ des
Resultats nicht bekannt ist.
Um solche Typinformationen zur Laufzeit bereit zu stellen, gibt es die Klasse
ResultSetMetaData, in der Operationen bereit gestellt werden, um z. B. die Anzahl der
Attribute und die Datenbanktypen des Resultats abzufragen. Ein Objekt der Klasse wird
dann durch
ResultSetMetaData rsmd = rs.getMetaData();
erzeugt. Danach kann man z. B. durch den Aufruf
Seite 142 von 159
Seite 143 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
5.2 Embedded SQL (eSQL, SQLJ)
int count = rsmd.getColumnCount();
basiert auf der Verwendung eines Vorübersetzers
statische Festlegung der Datenbankoperationen zur Übersetzungszeit
– Typenüberprüfung zwischen AWP und Datenbank durch den Vorübersetzer
– einfache Übertragung von Daten aus der Datenbank ins AWP
Verwendung des Cursor-Prinzips zum Durchlaufen von Relationen
die Anzahl der Attribute der Ergebnisrelation abfragen und mit
for (int i = 0; i < count; i++) {
int sqlType = rsmd.getColumnType(i);
…
Quelldateien
}
wird eine ganze Zahl geliefert, die den Typ des i-ten Attributs identifiziert. Für diesen
Typ kann dann z. B. die entsprechende get-Funktion aufgerufen werden.
Vor-Compiler
Zwischencode
Host-Compiler
DBMS-Bibliothek
Host-Linker
AWP
DBMS-Server
Seite 144 von 159
Seite 145 von 159
Anwendungsprogrammierung
Syntaktische Kennung von Datenbankoperationen im Java AWP:
#sql {SQL-Befehl}
Ein SQL-Befehl bezieht sich auf die Objekte der Datenbank. Eine Ausnahme sind die
sogenannten Hostvariablen, die zur Datenübertragung zwischen der Datenbank und dem
AWP genutzt werden.
–
Eine Hostvariable wird wie eine gewöhnliche Variable von Java deklariert und
genutzt.
–
Eine Hostvariable kann in einem SQL-Kommando genutzt werden, wobei dann dem
Variablennamen ein “:” vorgestellt ist.
Man kann nun auch Host-Variable auch dazu nutzen, Ergebnisse einer Anfrage
aufzunehmen, wobei nur ein Ergebnis geliefert wird. Dabei wird nun an die selectKlausel das Schlüsselwort into gefolgt von den Hostvariablen angehängt.
Beispiele
#sql {select A, B from R where B > :x}
Hier wird der Wert der Variable x in den SQL-Befehl eingesetzt.
#sql {select A, B into :a, :b from R where Id = 7}
Das Ergebnis wird nun in die Hostvariablen a und b übertragen (Ann.: Id ist Schlüsselkandidat).
Seite 146 von 159
Datenbank
Anwendungsprogrammierung
Öffnen einer Verbindung zu einer Datenbank
Ähnlich wie bei JDBC brauch man in SQLJ einen Bezug zu einer bestehenden
Datenbank. Aus diesem Grund können nun ein Kontext definiert werden:
#sql context verbinden
Danach kann nun verbinden wie eine Klasse benutzt werden, die insbesondere folgenden
Konstruktor besitzt:
verbinden verbindungsObject = new verbinden("jdbc:oracle:thin:@venus.mathematik.uni-marburg.de:1521:Init_DB", "scott", "tiger");
Dieses Kontextobjekt kann nun bei einem sql-Befehl noch zusätzlich angegeben werden:
#sql (verbindungsObject) {select A, B from R where B > :x}
Wird bei einem sql-Befehl kein Kontextobjekt angegeben, so wird ein
Defaultkontextobjekt genutzt.
Beim Übersetzen des SQLJ-Programms können bereits Überprüfungen erfolgen, die bei
JDBC erst zur Laufzeit möglich sind.
Seite 147 von 159
Anwendungsprogrammierung
Anfrageformulierung mit Iteratoren
Für SQL-Anweisungen, die mehr als eine Antwort liefern, können nun Iteratoren
(Cursor) definiert werden. Es wird unterschieden zwischen positionsbezogene und
namenbezogene Iteratoren.
Positionsbezogene Iteratoren (Beispiel):
–
Deklaration:
#sql public iterator Pos (String, int);
Damit wird ein Iteratortyp Pos mit zwei Komponenten definiert.
–
Danach kann man eine Variable des Typs deklarieren:
Pos x;
–
und ein sql-Befehl an diese Variable binden:
#sql x = {select A, B from R where B > 10};
–
Der Zugriff auf die Ergebnismenge erfolgt dann i. A. in einer Schleife:
while (true) {
#sql {fetch :x into :a, :b};
if (x.endFetch()) break;
System.out.println(a + “ verdient “ + b + “ DM”);
}
Anwendungsprogrammierung
Namenbezogene Iteratoren
– Deklaration:
#sql public iterator Name (String A, int B);
– Deklaration einer Variablen
Name y;
– Anbinden an einen SQL-Befehl:
#sql y = {select A, B from R where B > 10};
– Zugriff auf die Ergebnismenge:
while (y.next())
System.out.println(y.A() + “ verdient “ + y.B() + “ DM”);
Man beachte hierbei, daß der Zugriff auf die Werte über Methodenaufrufe erfolgt,
wobei der Name der Methode dem des Attributs entspricht.
Mit der Methode next wird auf das nächste Tupel zugegriffen.
Seite 148 von 159
Seite 149 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
Mengenwertige Änderungs- und Löschoperationen
Solche Operationen verwenden auch Iteratoren, wobei die zu ändernde (löschende)
Datenmenge an den Iterator gebunden wird.
Danach können folgendermaßen die Änderungen vorgenommen werden.
#sql public iterator Name (String A, int B);
…
Name y;
…
#sql y = {select A, B from R where B > 10};
…
while (y.next())
#sql {update R set B = B + 10 where current of :y}
5.3 PL/SQL: eine Spracherweiterung
PL/SQL ist eine von Oracle entwickelte Erweiterung von SQL um die Konzepte der
imperativen Programmierung
Syntax orientiert sich an die Programmiersprache Ada
Standardisierung ist in Arbeit (siehe SQL/PSM)
Vorteile gegenüber einer Hostsprache
homogene Anbindung der imperativen Konzepte an SQL
Typkonvertierungen entfallen
plattformunabhängige Ausführung
Nachteil:
Damit wird nun der derzeit angesprochene Datensatz der Menge geändert.
imperativen Konzepte sind für eine vollständige Entwicklung von AWP nicht
ausreichend.
Seite 150 von 159
Seite 151 von 159
Anwendungsprogrammierung
PL/SQL Block
Ein Block in PL/SQL ist folgendermaßen definiert:
[<header> IS]
[DECLARE <declarations>]
BEGIN
<Statements>*
[EXCEPTION <exceptions>]
END
Deklarationsteil:
Typdeklarationen
–
PL/SQL unterstützt insbesondere auch die Definition von Records:
type PersonTyp is record
// Record-Datentyp
(Name varchar(50)
Salary int);
–
Es gibt in PL/SQL Typen wie boolean, die es in SQL nicht gibt.
–
Weiterhin erlaubt PL/SQL auch noch indirekt über Relationen und Variablen
erzeugte Typen (siehe Variablendeklaration)
Anwendungsprogrammierung
Variablendeklarationen
– Eine Variable wird ähnlich wie bei Java durch Voranstellen des Typs deklariert:
PersonTyp ang;
– Eine Besonderheit ist insbesondere, daß die Datentypen der Relationen bei der
Variablendeklaration benutzt werden können:
meinBuch Bücher%rowtype;
– Entsprechend wird durch
deinBuch meinBuch%type;
eine Variable vom Typ der Variable meinBuch deklariert.
– Ähnlich wie in Pascal erstreckt sich der Gültigkeitsbereich einer Variablen auf den
lokalen Block und alle Blöcke, die in diesem enthalten sind.
Cursordeklarationen
– konstante Cursor
cursor AktBuch is
// Cursor-Deklaration ähnlich wie in JDBC
select *
from Bücher;
– parameterisierte Cursor
cursor interessantePersonen(von int, bis int) is
select *
from Personen
where Salary > von and Salary < bis;
Seite 152 von 159
Seite 153 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
Verarbeitungskontrolle
Prozeduren und Funktionen
Imperative Ablaufsteuerung
In PL/SQL ist es auch möglich Prozeduren und Funktionen zu deklarieren.
– Eine Prozedur ist ein Block, der mit einem Namen versehen ist und über eine
Parameterleiste verfügt.
– Eine Funktion liefert durch den Befehl return stets ein Ergebnis.
function totalSalary(int von, int bis) return int is
begin
declare p Personen%rowtype;
int total;
open interessantePersonen(von, bis);
…
return total;
end
– Prozeduren und Funktionen können die Parameter mit drei verschiedenen Optionen
versehen (in, out, in out)
procedure doit
(par1 in ParamTyp1, par2 out ParamTyp2, par3 in out ParamTyp3, …)
is
<PL/SQL-Anweisungen mit Zuweisungen an die OUT-Parameter>
bedingte Anweisung
if <Bedingung> then <PL/SQL-Anweisung> end if;
Schleife
for <IndexVariable> in <Bereich>
loop
<PL/SQL-Anweisung>
end loop;
Verarbeitung eines Cursors
Öffnen eines Cursors
open AktBuch;
open interessantePersonen(1000, 2000);
Verarbeitung einer Antwortmenge
–
spezielles Schleifenkonstrukt für einen Cursor
for meinBuch in AktBuch
loop
<PL/SQL-Anweisung>
end loop;
Seite 154 von 159
Seite 155 von 159
Anwendungsprogrammierung
Stored Procedures
Funktionen und Prozeduren können durch “create” im Datenbanksystem in übersetzter
Form abgespeichert werden und entsprechend aufgerufen werden.
–
Dies hat insbesondere den Vorteil gegenüber dem bisherigen Ansatz von PL/SQL,
daß die Anweisungen nicht mehr übersetzt werden müssen.
Die Deklaration einer Prozedur (Funktion) folgt dem bereites vorher erläuterten Muster
Cursor-Variablen
Es ist oft günstig die Ergebnisse einer Stored Procedures durch Cursor-Variablen an das
aufrufende PL/SQL-Programm zu geben.
Eine Cursor-Variable ist eine Referenz auf eine Liste von Datensätzen. Folgende Typen
von Cursor-Variablen gibt es:
–
starker Typ:
type personenCurTyp is ref cursor Personen%rowtype;
–
schwache Typ:
type allCurTp is ref cursor;
Die Variablendeklaration wird wie üblich vorgenommen.
Man beachte, daß zum Zeitpunkt der Deklaration die Cursor-Variable noch keinen Bezug
zu einer Anfrage hat.
Anwendungsprogrammierung
Anbindung an Anfragen einer Cursor-Variable
– Wird ein Cursor geöffnet, wird nun dir Variable an eine Anfrage gebunden:
open personenCurTyp for
select * from Personen where Sal > 1000;
typische Verwendung
– Öffnen einer Cursor-Variable in der Stored Procedure (Function)
– Übergeben des Cursors an das AWP, wo dann die Datensätze verarbeitet werden.
Trotz der vielen Vorteile, die Cursor-Variablen bieten, gibt es derzeit bei der Nutzung in
Oracle noch sehr viele Einschränkungen:
– Eine Cursor-Variable darf nicht im Update-Modus geöffnet werden.
– Der Typ ref cursor gibt es nur in PL/SQL, aber nicht in SQL (siehe unten).
– … (siehe Handbücher)
Seite 156 von 159
Seite 157 von 159
Anwendungsprogrammierung
Anwendungsprogrammierung
Stored Functions in SQL
Gespeicherte Funktionen können innerhalb von SQL deklariert und auch aufgerufen
werden. Es gelten natürlich wieder einige Einschränkungen:
–
Die Funktion enthält keine Gruppierungsoperationen.
–
Alle Datentypen der Eingabe und der Ausgabe müssen im Datenbanksystem
bekannt sein.
Beispiel einer gespeicherten Funktion:
create function simple(x in int) return int as begin return x / 101; end simple;
Beispiel einer SQL-Anfrage:
select Name, simple(Sal) from Personen;
Fazit
PL/SQL ist eine interessante Erweiterung von SQL, die schon vor Java eine
plattformunabhängige Programmierung angeboten hatte.
SQL wird insbesondere durch Stored Functions mächtiger
Leider sind die Konzepte wie Cursor nicht orthogonal verwendbar. Es gibt viele
Einschränkungen, was das Leben bei der Programmierung sehr schwierig macht.
Seite 158 von 159
5.4 Weitere Kopplungsmöglichkeiten
PASCAL/R: eine Erweiterung von Pascal für relationale Datenbanken
Erweiterung des Typsystems von PASCAL:
– Datentyp RELATION entspricht “SET OF TUPLE”
– Operationen der relationalen Algebra
– Iteratoren (wie Cursor) für die Verarbeitung von Relationen
Skriptsprachen
populärer Ansatz für die Erstellung von AWPs (z. B. Visual Basic)
Nachteil
– keine strenge Typisierung
– keine Standards (schlechte Wartung der Applikationssoftware)
– Durchmischung von verschiedenen Konzepten aus dem Bereich Datenbank,
imperativen Programmierung, Benutzerschnittstellen und Regeln
Vorteil:
– schnelle Erstellung von AWP mit graphischen Benutzeroberflächen
– komfortable Entwicklungsumgebung
Seite 159 von 159
Herunterladen