jdbc - ssw.jku.at

Werbung
Java Database Connectivity API / JDBC
Motivation
Design
Treiber
Grundlagen
Metadaten
Transaktionen
Exceptions
Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer
1
Motivation
•! Problem: Zugriff auf DBMS nicht einheitlich
Anwendung
Anwendung
Anwendung
MySQL API
DB2 API
Oracle API
MySQL
DB2
Oracle
2
Motivation
•! Lösung: Zwischenschicht
MySQL API
Anwendung
JDBC API
J
D
B
C
DB2 API
Oracle API
MySQL
DB2
Oracle
3
Design
•!
•!
•!
•!
•!
Entwicklung seit: 1995
Erster Ansatz: Java erweitern
Zweiter Ansatz: Treiber der Datenbankhersteller
Vorbild: ODBC
Unterschiede:
–! ODBC wenige Befehle, viele Optionen
–! JDBC viele einfache Methoden
–! ODBC nutzt void-Zeiger
–! Java kennt keine Zeiger
•! Flexibilität: JDBC erlaubt beliebige Zeichenfolgen
–! Anpassung an Datenbank möglich.
•! Optimierung !
•! Bindung "
4
Design
Java Anwendung
JDBC-Treibermanger
JDBC/ODBCBrücke
JDBC-Treiber
ODBC-Treiber
Datenbank
Datenbank
5
Treiber, Typ 1 und 2
•! Typ 1: Brücke
–! zB: JDBC/ODBC
•! ODBC ist verbreitet !
•! Testen, Experimentieren
•! Windows Plattformen
–! Leistung "
–! Wartung "
–! Wenn kein JDBC-Treiber
verfügbar ist
ODBC
ODBCTreiber
DB
Server
Client
•! Typ 2: Partial Java Driver
–! Gibt Aufruf an native
API weiter
–! DB und OS abhängig "
–! Nutzer braucht
plattformabhängige API "
B
r
ü
c
k
e
JDBCAnwendung
JDBCAnwendung
Client
A
P
I
DB
Server
6
Treiber, Typ 3 und 4
•! Typ 3: Reiner Java Treiber zu Middleware
–!
–!
–!
–!
Portabel !
DB unabhängig !
Flexibel, mehrere DB möglich !
DB abhängiger Teil in Middleware
•! Typ 4: Reiner Java Treiber zur DB
JDBCAnwendung
Client
–! Portabel !
–! Schnell !
JDBC–! Verbindung
Anwendung
•! Netz
•! File I/O
•! Embedded
Client
–! Client braucht DB abhängige Treiber "
M
W
DB
Server
Server
DB
Server
7
Treiber, Installation
•! Download
–! http://developers.sun.com/product/jdbc/drivers
–! Datenbankhersteller
•! Installation
–! Eintragen in den Klassenpfad
•! Laden eines JDBC Treibers
–! System Property: jdbc.drivers
•! java -Djdbc.drivers=org.apache.derby.jdbc.EmbeddedDriver Xyz
•! System.setProperty("jdbc.drivers",
"org.apache.derby.jdbc.EmbeddedDriver");
–! Manuelles laden der Treiberklasse
•! Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
–! Automatisch durch DriverManager
•! Java Service: java.sql.Driver
8
Verbindungsaufbau
•! 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
•! jdbc:derby:/path/to/Database
•! jdbc:derby:Database
–! MySQL
•! jdbc:mysql://<host>:<port>/<Database>
!"#$%&'()*+,-)
9
Verbindung
•! Connection: Verwaltet Verbindung (Session) zur DB
–! close()
•! Schließen der Verbindung
–! commit()
•! Bestätigen vorangegangener Änderungen, Standard
ist auto-commit
–! Statement createStatement()
Statement stat = con.createStatement();
stat.executeUpdate("INSERT INTO test VALUES ('Hallo')");
–! PreparedStatement prepareStatement(String sql)
PreparedStatement stat = con
.prepareStatement("INSERT INTO test VALUES ('Hallo')");
...
stat.executeUpdate();
10
Statement
Parameterlos!
•! ResultSet executeQuery(String sql)
SQL-Injection
–! Ausführen einer SQL-Abfrage (SELECT)
•! int executeUpdate(String sql)
–! Ausführen eines Updates (UPDATE, INSERT, DELETE)
–! Liefert die Anzahl der betroffenen Zeilen
•! boolean execute(String sql)
–! Ausführen beliebiger SQL-Anweisungen
–! Liefert true wenn eine Ergebnismenge geliefert wurde
•! int getUpdateCount()
–! Anzahl der betroffenen Zeilen, oder -1 wenn Anweisung keinen
Zähler hatte
•! ResultSet getResultSet()
–! Ergebnismenge der letzten Abfrage, oder null wenn keine
Ergebnismenge geliefert wurde
•! void close()
–! Gibt alle JDBC Ressourcen frei
11
PreparedStatement
•! void set<Typ>(int n, <Typ> x)
90% Lösung
–! Setzen des Parameters an der Stelle n (1..m)
•! void clearParameters()
–! Löschen aller Parameterwerte
•! ResultSet executeQuery()
–! Ausführen der vorübersetzten SQL-Anfrage (SELECT)
•! int executeUpdate()
–! Ausführen des vorübersetzten Updates (UPDATE, INSERT, DELETE)
–! Gibt die Anzahl betroffener Zeilen zurück
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();
12
CallableStatement
•! Ausführen von DB-Prozeduren (SQL stored procedures)
•! Parameterlose Prozedur
–! {call procedure_name }
•! Prozedur
–! {call procedure_name(?,?,...)}
•! Funktion
–! { ? = call procedure_name(?,?,...) }
•! Eingangsparameter analog zu PreparedStatement
•! Ausgabeparameter müssen registriert werden
–! void registerOutParameter(int index, int sqlType)
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);
13
Batch Statements
•! Kommandos Anfügen
–! Statements: void addBatch(String sqlCmd)
–! PreparedStatements: void addBatch()
•! Löschen der Kommandos: void clearBatch()
•! Ausführen der Kommandos: int[] executeBatch()
Statement stmt = conn.createStatement();
stmt.addBatch("insert into Person values(5, 'Herman', 'Hollerith', 1983)");
stmt.addBatch("insert into Person values(6, 'Larry', 'Ellison', 1977)");
int[] upds = stmt.executeBatch();
PreparedStatement pStmt =
conn.prepareStatement("insert into Person values(?, ?, ?, ?)");
for (Person p : persons) {
pStmt.setInt(1, p.getId()); pStmt.setString(2, p.getFirstName());
pStmt.setString(3, p.getLastName()); pStmt.setInt(4, p.getYear());
pStmt.addBatch();
}
int[] res = pStmt.executeBatch();
14
ResultSet
•! ResultSet ist die Ergebnistabelle einer Abfrage
•! Arten
–!
–!
–!
–!
einfache: können nur sequentiell von vorne nach hinten durchlaufen werden
scrollbare: erlaubt beide Richtungen und Positionierung
änderbare: erlauben Änderungen in der Datenbank
sensitive: zeigen Änderungen in Datenbank an
•! Art beim Erzeugen des Statements festlegen:
ResultSet.TYPE_FORWARD_ONLY
ResultSet.TYPE_SCROLL_INSENSITIVE
ResultSet.TYPE_SCROLL_SENSITIVE
Statement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability) throws SQLException
ResultSet.CONCUR_READONLY
ResultSet.CONCUR_UPDATABLE
ResultSet.HOLD_CURSORS_OVER_COMMIT
ResultSet.CLOSE_CURSORS_AT_COMMIT
15
ResultSet Lesen
•! Zeilenweise abarbeiten der Ergebnistabelle
–! boolean next()
•! Anspringen der nächsten Zeile
•! true solange gültige Zeile erreicht wird
•! ResultSet beginnt vor der ersten Zeile
–! <Typ> get<Typ>(int spalte)
–! <Typ> get<Typ>(String spaltenName)
–! boolean wasNull()
•! true wenn letzter Wert SQL-NULL war
–! int findColumn(String spaltenName)
!"# !$%&# '(&#
getInt(3) => 25
wasNull() => false
getString("Name") => Max
findColumn("Nr") => 1
next()
*)
.$/)
,+)
,)
0%1')
,-)
222) 222)
222)
16
ResultSet Navigation
•! boolean first()
–! Erste Zeile im ResultSet
–! true wenn gültige Zeile erreicht
•! void beforeFirst()
–! Vor die erste Zeile im ResultSet
•! boolean last()
–! Letzte Zeile im ResultSet
–! true wenn gültige Zeile erreicht
•! void afterLast()
–! Nach letzter Zeile im ResultSet
•! boolean absolute(int row)
–! Eine Zeile anspringen
•! row > 0 ... von oben (1 erste Zeile, 2 zweite Zeile, ...)
•! row < 0 ... von unten (-1 letzte Zeile, -2 vorletzte Zeile, ...)
–! true wenn gültige Zeile erreicht
•! int getRow()
–! Nummer der aktuellen Zeile
17
ResultSet Update
•! void update<Typ>(int col, <Typ> x)
–! ändert die aktuelle Zeile
•! void updateRow()
–! schreibt die aktuelle Zeile in die Datenbank zurück
•! void moveToInsertRow()
–! bewegt den Cursor auf die "insert row"
•! void insertRow()
–! der Cursor muss vorher mit moveToInsertRow() auf die "insert
row" bewegt werden.
–! fügt eine neue Zeile in die Datenbank ein
•! void deleteRow()
–! löscht aktuelle Zeile aus der Datenbank
18
Typen
SQL-Typ
Java-Typ
CHAR, VARCHAR, LONGVARCHAR
String
NUMERIC, DECIMAL
java.math.BigDecimal
BIT
boolean
TINYINT
byte
SMALLINT
short
INTEGER
int
BIGINT
long
REAL
float
FLOAT, DOUBLE
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
19
Metadaten, Datenbank
•! Erstellen über Verbindung
–! DatabaseMetaData <Connection>.getMetaData()
•! Allgemeines
–!
–!
–!
–!
Connection getConnection()
String getURL()
String getUserName()
boolean isReadOnly()
•! Eigenschaften
–! boolean supportsANSI92EntryLevelSQL()
–! boolean supportsTransactions()
–! boolean supportsGroupBy()
•! Beschränkungen
–! int getMaxStatementLength()
–! int getMaxStatements()
–! int getMaxConnections()
0 .. kein Limit oder
unbekannt
20
Metadaten, Tabellen
•! ResultSet getTables(String catalog, String schema,
String table, String[] types)
•! ResultSet getColumns(String catalog, String schema,
String table, String column)
–! catalog: Name des Katalogs
•! "" Tabellen ohne Katalog, null Katalognamen nicht
berücksichtigen
–! scheme: Schemaname
•! "" Tabellen ohne Schema, null nicht berücksichtigen
–! table: Tabellenname
•! null nicht berücksichtigen
–! column: Spaltenname
•! null nicht berücksichtigen
–! types:
•! zB: "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
"LOCAL TEMPORARY", "ALIAS", "SYNONYM"
•! null nicht berücksichtigen
21
Metadaten, Ergebnismenge
•! Erstellen
–! ResultSetMetaData <ResultSet>.getMetaData()
•! Eigenschaften
–!
–!
–!
–!
–!
–!
Nr Name Title ... Age
int getColumnCount()
1
String getColumnName(int!column)
2
int getColumnType(int!column)
...
String getColumnTypeName(int!column)
String getTableName(int!column)
boolean isCurrency(int column)
getColumnCount() => 3
getColumnName(1) => "Nr"
getColumnType(3) => 4 // INTEGER
getColumnTypeName(3) => "int"
getTableName(2) => "users"
Max
DI
... 30
Susi
Mag ... 28
...
...
... ...
SELECT Nr,
Name, Age
FROM users;
Nr Name Age
1
Max
30
2
Susi
28
...
...
...
22
Transaktionen
•! Standard: auto-commit, jedes Statement eine Transaktion
–! boolean <Connection>.getAutoCommit()
–! void <Connection>.setAutoCommit(boolean ac)
•! Transaktion startet automatisch
•! Transaktion abschießen
Auto-Commit
–! void <Connection>.commit()
•! Transaktion rücksetzen (zB: SQLException)
–! void <Connection>.rollback()
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(); }
Savepoints
TransactionIsolation
NONE
READ_UNCOMMITTED
READ_COMMITTED
REPEATABLE_READ
SERIALIZABLE
23
Exceptions
SQLException
SQLNonTransient
Exception
Erneuter
Versuch wird
fehlschlagen
SQLTransient
Exception
Erneuter
Versuch kann
durchgehen
SQLRecoverable
Exception
Erneuter Versuch
nach Eingriffen
kann durchgehen
24
JavaDB, Derby
•! Seit Java 6.0 mitgeliefert
•! Web-Seite: http://db.apache.org/derby
•! Umgebungsvariablen
–! JAVA_HOME=Pfad zur Java JDK Installation
–! DERBY_HOME=Pfad zur Derby Installation
–! PATH um DERBY_HOME/bin erweitern
•! JARs in DERBY_HOME/lib
–!
–!
–!
–!
–!
derby.jar, Engine, 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
derbynet.jar
25
JavaDB, Derby Installation & Treiber
•! DERBY_HOME (Windows)
–! C:\Programme\Sun\JavaDB
•! Derby Hilfsprogramme
–! DERBY_HOME\bin
•! Derby Driver
–! org.apache.derby.jdbc.ClientDriver
–! org.apache.derby.jdbc.EmbeddedDriver
•! Derby Connection-String
–! jdbc:derby://localhost:1527/Name_of_DB
Derby Network–! jdbc:derby:Name_of_DB
Embedded, Zugriff auf
Dateien: Nur eine
Verbindung möglich!
Server muss
gestartet sein!
26
JavaDB, Derby, Kommandozeilen-Werkzeuge
•! Systeminformation: sysinfo
27
JavaDB, Derby, Kommandozeilen-Werkzeuge
•! Kommandozeilenwerkzeug: ij
Verbinden zu (und evtl.
erzeugen einer)
Datenbank
Tabelle erzeugen
Beschreibung einer Tabelle
28
JavaDB, Derby, Kommandozeilen-Werkzeuge
•! Kommandozeilenwerkzeug: ij
Einfügen eines Datensatzes
Aktualisieren eines Datensatzes
Löschen einer Tabelle
29
Zusammenfassung
•! Datenbankunabhängigkeit
–! Zwischenschicht -> einfachere Programmentwicklung
–! Treiberschnittstelle (min. SQL 92 entry level)
•! 4 Treiberarten
–! Brücke (zB: JDBC -> ODBC)
–! Teilweise Java
–! Java zu Middleware
–! Java zu Datenbank
•! Beliebige SQL-Kommandos absetzbar
–! Optimierung vs. Datenbankunabhängigkeit
•! Statements
–! PreparedStatement
•! Vorkompiliert, mit Parametern (Sicher gegen SQL-Injection)
–! Statement
•! Statisch, Abfragen vom Benutzer, keine Parameter
–! CallableStatement
•! Stored Procedures, mit IN, OUT und INOUT Parametern
30
Herunterladen