Protokoll Stunde 7

Werbung
Praktikum aus Softwareentwicklung 2, Stunde 7
Lehrziele/Inhalt
1. Datenbanken
Datenbanken
Datenbanken werden in Java über JDBC (ist ein Eigenname, wird aber oft als Abkürzung von Java
Database Connectivity API gesehen) angesprochen. JDBC ist eine Abstraktionsschicht über
Datenbanktreibern. Ohne Abstraktion müsste man bei einem Datenbankwechsel die Anwendung
umprogrammieren.
Design von JDBC
JDBC wird seit 1995 entwickelt, erste Überlegungen gingen in Richtung einer Spracherweiterung,
diese Ideen wurden aber verworfen und eine Treiberschnittstelle für Drittanbieter gebaut. JDBC
lehnt sich an ODBC an, aber im Stil von Java: ODBC hat wenige Befehle aber sehr viele Optionen,
JDBC hat viele einfache Methoden. Außerdem benutzt ODBC void-Zeiger und Java kennt keine Zeiger.
Befehle an die Datenbank werden als String übergeben. Das erlaubt es Programmieren SQL-Befehle
für eine Datenbank zu optimieren, aber man muss sich bewusst sein, dass eine solche Optimierung
wieder eine Bindung an eine Datenbank bedeutet.
Treiberarten in JDBC
Es gibt vier Treiberarten in JDBC. Sie sind historisch bedingt: der Typ 1 Treiber ist ein Brücke von JDBC
nach ODBC, vom Typ 2 ist ein Treiber wenn er aufrufe an native Treiber weiterleitet, vom Typ 3 ist
ein Treiber wenn er voll in Java implementiert ist und an eine Middleware bindet und vom Typ 4 ist
ein Treiber der voll in Java implementiert ist und direkt eine Datenbank ansprechen kann.
Typ 1: Brücke
Typ 1 die Brücke von JDBC nach ODBC war ein pragmatischer Ansatz von Sun, um vom Start weg so
viele Datenbanken wie möglich anbinden zu können. Für ODBC waren damals viele Datenbanktreiber
verfügbar. Nachteile dieses Ansatzes sind: die zusätzliche ODBC-Schicht kostet Leistung; höhere
Wartung, es muss am Zielrechner ein ODBC-Treiber installiert und gepflegt werden.
Typ 2: Partial Java Driver
Gibt Aufrufe direkt an eine native Implementierung weiter. Da für Datenbanken native Treiber
vorhanden waren, war dies eine Möglichkeit für Datenbank-Hersteller schnell Java-Treiber
anzubieten. Der Nachteil dieses Ansatzes ist die Betriebssystemabhängigkeit der Treiber.
Typ 3: Reiner Java Treiber zu einer Middleware
Der Treiber ist völlig in Java implementiert und damit Betriebssystemunabhängig. Durch die
Middleware ist das Programm auch Datenbankunabhängig. Nachteile: es muss einen Server geben
wo diese Middleware installiert ist.
© Markus Löberbauer 2010
Seite 22
Typ 4: Reiner Java Treiber zu einer Datenbank
Der Treiber ist völlig in Java implementiert und dadurch Betriebssystemunabhängig. Typ 4 Treiber
verbinden direkt auf die Datenbank und sind damit schnell. Ein kleiner Nachteil gegenüber Typ 3 ist
die Abhängigkeit von der Datenbank.
Installation von JDBC-Treibern
Datenbanktreiber für JDBC kann man auf http://developers.sun.com/product/jdbc/drivers oder bei
den Datenbankherstellerseiten finden. Zur Installation muss man den Treiber in den Klassenpfad
aufnehmen.
Will man einen Treiber benutzen, muss man ihn laden, dazu hat man die Möglichkeiten:
a. System Property: jdbc.drivers, zB:
a. java -Djdbc.drivers=org.apache.derby.jdbc.EmbeddedDriver Xyz
b. System.setProperty("jdbc.drivers", "org.apache.derby.jdbc.EmbeddedDriver");
b. Manuelles laden der Treiberklasse, zB:
a. Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
c. Seit JDBC 4 (Java 6.0), Laden als Java Service durch DriverManager, dazu muss der Treiber
das Java Service java.sql.Driver anbieten
Aufbauen einer Verbindung
Eine Verbindung (Connection) zu einer Datenbank kann man über DriverManager.getConnection
aufbauen. Dazu muss man eine Datenbank-Url und optional einen Benutzernamen und Passwort
angeben.
DriverManager: Verwaltet registrierte Treiber, baut Verbindungen auf

Connection getConnection(String url, String user, String password)
Datenbank URL




Aufbau: jdbc:<subprotrokoll>:<subname>
jdbc:<Datenbanktreiber>:<treiberspezifische Angaben>
Derby
o jdbc:derby:/path/to/Database
o jdbc:derby:Database
MySQL
o jdbc:mysql://<host>:<port>/<Database>
Arten von Statements
Über die Connection kann man die Verbindung zur Datenbank verwalten, zB schließen,
Informationen über die Datenbank abfragen, Transaktionen verwalten und Statement-Objekte
anfordern. JDBC unterscheidet die Statement-Arten: Statement, PreparedStatement und
CallableStatement

Statement (Connection.createStatement): Absetzen von beliebigen SQL-Befehlen, einsetzbar
für Werkzeuge, bei denen der Benutzer den Befehl eingeben kann und für vordefinierte
Befehle.
© Markus Löberbauer 2010
Seite 23
Beispiel:
Statement stat = con.createStatement();
stat.executeUpdate("INSERT INTO test VALUES ('Hallo')");

PreparedStatement (Connection.prepareStatement): Absetzen von SQL-Befehlen mit
Parametern, einsetzbar wenn Benutzer Parameter eingeben können. Parameter werden mit
einem „?“ in den SQL-String eingesetzt, und mit set-Methoden vor dem Ausführen über ihre
Position gesetzt, Positionen werden von 1 ab gezählt. Verhindert SQL-Injection. Kann auf der
Datenbank vorkompiliert werden und ist damit schneller bei der Ausführung.
Beispiel:
PreparedStatement stat;
stat = con.prepareStatement("INSERT INTO test VALUES (?,?)");
stat.setString(1, "Hallo");
stat.setString(2, "Welt");
stat.executeUpdate();
stat.setString(2, "Jane");
stat.executeUpdate();

CallableStatement (Connection.prepareCall): Ausführen von Datenbank-Prozeduren.
CallableStatements können wie PreparedStatements parametrisiert werden.
Ausgangsparameter werden unterstützt, sie müssen aber registriert werden
(registerOutParameter). Übergangsparameter müsse ebenfalls als Ausgangsparameter
registriert werden.
Beispiel:
CallableStatement cs = con.prepareCall("{ CALL GET_NUMBER_FOR_NAME(?, ?) }");
cs.registerOutParameter(2, java.sql.Types.INTEGER);
cs.setString(1, "Duke");
cs.execute();
int number = cs.getInt(2);
Abfragen der Ergebnisse
Statements liefern Abfrageergebnisse als ResultSet zurück. ResultSet ist ein Cursur, es funktioniert
wie ein Iterator von dem man Werte abfragen kann. Am Anfang steht das ResultSet vor der ersten
Zeile, mit boolean next() kann man die nächste Zeile anspringen, der Rückgabewert von next gibt an
ob eine gültige Zeile erreicht wurde.
Die Werte einer Zeile können mit Methoden der Art get<Typ>(int spalte) und get<Typ>(String
spaltenName) abgefragt werden. Fragt man einen Wert ab, kann man mit wasNull abfragen ob der
Wert in der Datenbank SQL-NULL ist. Folgende weitere Methoden stehen zur verfügung:



int findColumn(String spaltenName): sucht die Spaltennummer zu einer Spalte mit
gegebenem Spaltennamen.
boolean first(): Springt in die erste Zeile im ResultSet, liefert true wenn gültige Zeile erreicht
wird.
void beforeFirst(): Springt vor die erste Zeile im ResultSet.
© Markus Löberbauer 2010
Seite 24




boolean last(): Springt in die letzte Zeile im ResultSet, liefert true wenn gültige Zeile erreicht
wird.
void afterLast(): Springt hinter die letzte Zeile im ResultSet.
boolean absolute(int row): Spring in die Zeile mit der gegebenen Nummer:
o row > 0 ... von oben (1 erste Zeile, 2 zweite Zeile, ...)
o row < 0 ... von unten (-1 letzte Zeile, -2 vorletzte Zeile, ...)
o liefert true wenn gültige Zeile erreicht wird.
int getRow(): Liefert die Nummer der aktuellen Zeile
Abbildung der SQL-Typen auf Java-Typen
SQL-Typ
CHAR, VARCHAR, LONGVARCHAR
NUMERIC, DECIMAL
BIT
TINYINT
SMALLINT
INTEGER
BIGINT
REAL
FLOAT, DOUBLE
Java-Typ
String
java.math.BigDecimal
boolean
byte
short
int
long
float
double
BINARY, VARBINARY, LONGVARBINARY
byte[]
DATE
java.sql.Date
TIME
java.sql.Time
TIMESTAMP
java.sql.Timestamp
…
siehe JSR-221, Appendix B, Date Type Conversion Tables
Metadaten einer Datenbank
Über DatabaseMetaData Connection.getMetadata() kann man auf Informationen der Datenbank
zugreifen. Das ist wichtig wenn man Programme entwickelt, die die Datenbank nicht kennen, zB:
Administrationsoberflächen; oder wenn man die Datenbank bei der ersten Verwendung initialisieren
will.
Es kann auf Daten wie die Datenbank-Url (getURL), den Benutzernamen (getUserName) und
Beschreibbarkeit (isReadOnly) zugegriffen werden. Man abfragen was eine Datenbank unterstützt,
zB: Transaktionen (supportsTransactions), Gruppierung (supportsGroupBy). Welche Beschränkungen
eine Datenbank hat, zB: Maximale Länge eines Statements (getMaxStatementLength), Maximale
Anzahl der parallel absetzbaren Statements (getMaxStatements) und Maximale Anzahl geöffneter
Verbindungen (getMaxConnections). Wird bei den Beschränkungen 0 geliefert, bedeutet das, dass
keine Beschränkung gibt oder die Beschränkung unbekannt ist. Und man inhaltsbezogene Daten
abfragen, zB: welche Tabellen in einer Datenbank liegen, welche Spalten in einer Tabelle existieren
und welche Typen die Spalten haben.
© Markus Löberbauer 2010
Seite 25
Daten über Ergebnistabellen kann man über ResultSetMetaData ResultSet.getMetaData() abfragen.
Darüber kann man beispielsweise abfragen wie viele und welche Spalten geliefert werden; welche
Typen und Namen die Spalten haben und ob man auf eine Spalte schreiben kann.
Transaktionen
Eine Transaktion wird in JDBC gestartet, sobald man ein Statement absetzt und noch keine
Transaktion läuft. Standardmäßig wird in JDBC jedes Statement als eine Transaktion behandelt.
Braucht man länger laufende Transaktionen, dann muss man die Eigenschaft autoCommit der
Verbindung auf false setzen (Conncetion.setAutoCommit). Eine laufende Transaktion kann man mit
Connection.commit abschließen und mit Connection.rollback rücksetzen. Zusätzlich kann man
während einer Transaktion Sicherheitspunkte (Savepoints) angelegen auf die man mit einem Rollback
zurückspringen kann.
Unterstützte Transaktions-Isolation
Welcher Transaktions-Isolations-Level von einer Datenbank unterstützt wird kann man über
DatabaseMetaData. supportsTransactionIsolationLevel abfragen. Die in JDBC bekannten
Transaktionslevels sind in der Klasse Connection definiert:





NONE: Kein Transaktionssupport => kein JDBC Treiber
READ_UNCOMMITTED: dirty reads, non-repeatable reads und phantom reads können
auftreten
READ_COMMITTED: dirty reads sind verhindert; non-repeatable reads und phantom reads
können auftreten
REPEATABLE_READ: dirty reads und non-repeatable reads sind verhindert; phantom reads
können auftreten
SERIALIZABLE: dirty reads, non-repeatable reads und phantom reads sind verhindert.
Beispiel:
Connection con;
...
try {
con.setAutoCommit(false);
Statement stat = con.createStatement();
stat.executeUpdate("INSERT ...");
stat.executeUpdate("INSERT ...");
stat.executeUpdate("UPDATE ...");
con.commit();
} catch (SQLException e) { con.rollback(); }
Ausnahmebehandlung
Alle JDBC-bezogenen Exceptions erben von SQLException, seit Java 6.0 gibt es eine feingranulare
Aufteilung in die Fehlerklassen: SQLNonTransientException, SQLTransientException und
SQLRecoverableException. Nicht-transient bedeutet, dass ein erneuter Versuch wieder fehlschlagen
wird; transient bedeutet, dass ein erneuter Versuch durchgehen kann; und recoverable bedeutet,
dass ein erneuter Versuch mit geänderten Daten durchgehen kann.
Java DB (Derby)
Seit Java 6.0 wird die Datenbank Java DB mit dem JDK geliefert. Diese Datenbank ist auch unter dem
Namen Derby oder Apache Derby bekannt. Derby ist eine kompakte (Kern: 2,5MB), in Java
© Markus Löberbauer 2010
Seite 26
entwickelte, einfach zu nutzende (ohne Installation), standardkonforme (SQL 99) Datenbank.
Interessant ist auch, dass die erzeugten Daten-Dateien betriebssystemunabhängig sind.
Will man von der Konsole aus mit Derby Arbeiten muss man die Umgebungsvariablen JAVA_HOME,
DERBY_HOME und PATH setzen:



JAVA_HOME=Pfad zur Java JDK Installation
DERBY_HOME=Pfad zur Derby Installation
PATH um DERBY_HOME/bin erweitern
In DERBY_HOME sind die jar-Dateien von Derby:





derby.jar: Kern, genügt für embedded DB
derbynet.jar: Netzzugriff, Serverseitig
derbyclient.jar: Netzzugriff, Clientseitig
derbytools.jar: Verwaltungs-Werkzeuge
derbyrun.jar verweist auf: derby.jar, derbyclient.jar, derbytools.jar und derbynet.jar
Auf die Verwaltungs-Werkzeuge in derbytools.jar kann man über Batch-Dateien zugreifen. Das
Werkzeug sysinfo liefert Informationen über die Java-Installation auf dem System; mit dblook kann
man das Datenbankschema exportieren. ij ist eine Konsole mit der man SQL-Befehle an eine
Datenbank absetzen kann.
© Markus Löberbauer 2010
Seite 27
Herunterladen