Die Java JDBC API definiert eine Vielzahl von Methoden, über die auf alle gängigen Datenbanken zugegriffen werden kann. Sie stellt eine transparente Zwischenschicht dar, um Inhalte von Datenbanken verschiedener Hersteller mit einheitlichen Aufrufen zu lesen und zu schreiben. Somit ist nicht nur ein schneller und unkomplizierter Wechsel von einer Datenbank zu einer anderen möglich, sondern es können auch Softwaresysteme entwickelt werden, die durch geschickte Parametrisierung den Zugriff auf verschiedene Datenbanksysteme erlauben.
Zwar wird mit der JDBC API eine einheitliche Schnittstelle angeboten, jedoch werden die spezifischen Klassen jeweils von den Datenbankanbietern realisiert. Deshalb müssen diese Klassen, die in der Regel als .jar Dateien zur Verfügung stehen, zunächst einmal beschafft und dann zur Laufzeit über den Java CLASSPATH eingebunden werden.
Für jeden Zugriff auf eine Datenbank wird zunächst einmal eine Connection
benötigt
und an diese Connection
gelangt man in der Regel über die Registrierung eines Treibers
seiner datenbankspezifischen URL, einem User-Namen und dem zugehörigen Passwort:
import java.sql.*; public class JdbcConExample { public static void main(String[] args) throws Exception { Class.forName("oracle.jdbc.driver.OracleDriver"); String dbUrl = "jdbc:oracle:thin:@myHostName:1521:myDatabaseName"; Connection con = DriverManager.getConnection(dbUrl, "scott", "tiger"); try { // Exec Database calls ... } finally { con.close(); } } }
Vendor | Driver-Class / Database-URL | Driver-Lib |
---|---|---|
DB2 | COM.ibm.db2.jdbc.net.DB2Driver jdbc:db2://{host}[:{port}]/{dbname} |
db2java.zip |
Derby | org.apache.derby.jdbc.EmbeddedDriver bzw. org.apache.derby.jdbc.ClientDriver jdbc:derby://server[:port]/databaseName[;URLAttributes=value[;...]] |
derby.jar |
HSQLDB | org.hsqldb.jdbcDriver jdbc:hsqldb[:{dbname}][:hsql://{host}[/{port}]] |
hsqldb.jar |
MS SQL-Server | com.microsoft.jdbc.sqlserver.SQLServerDriver jdbc:microsoft:sqlserver://{host}[:{port}][;DatabaseName={dbname}] |
msbase.jar mssqlserver.jar msutil.jar |
MySQL | com.mysql.jdbc.Driver jdbc:mysql://{host}[:{port}]/[{dbname}] |
mysql-connector-java-5.1.5-bin.jar |
Oracle | oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@{host}:{port}:{dbname} |
classes12.zip |
Postgre | org.postgresql.Driver jdbc:postgresql://[{host}[:{port}]]/{dbname} |
pgdev.307.jdbc3.jar |
Der Zugriff auf die Datenbanken folgt im Wesentlichen immer nach dem gleichen Schema. Wichtig in diesem
Zusammenhang ist lediglich, peinlich darauf zu achten, dass geöffnete Ressourcen wie
ResultSet
s und PreparedStatement
s nach ihrer Verwendung auf jeden Fall
wieder geschlossen werden, denn sonst kann es zu unangenehmen Überraschungen wie beispielsweise
Out-Of-Memory Fehlern kommen. Wichtig ist weiterhin, String-Werte in Select-Statements mit Hochkommas
wie hier bei 'StringValue' zu begrenzen:
void selectTemplate() throws Exception { ResultSet rs = null; PreparedStatement ps = null; try { ps = con.prepareStatement("SELECT * from MyDB"); rs = ps.executeQuery(); while (rs.next()) { String content = rs.getString("fieldName"); // ... } } finally { if (rs != null) try { rs.close(); } catch (Exception ex) { /* ex.printStackTrace(); */ } if (ps != null) try { ps.close(); } catch (Exception ex) { /* ex.printStackTrace(); */ } } }
int insertTemplate() throws Exception { PreparedStatement ps = null; try { Sting stmt = "INSERT INTO MyDB (Field_1,Field_2,Field_n) VALUES (1,'string_val_2',4711)" ps = con.prepareStatement(stmt); return ps.executeUpdate(); // num rows affected } finally { if (ps != null) try { ps.close(); } catch (Exception ex) { /* ex.printStackTrace(); */ } } }
int updateTemplate() throws Exception { PreparedStatement ps = null; try { Sting stmt = "UPDATE MyDB SET Field_1 = 1, Field_2 = 'string_val_2', Field_n = 4711 " + "WHERE Index_Field = 'Index-Value'" ps = con.prepareStatement(stmt); return ps.executeUpdate(); // num rows affected } finally { if (ps != null) try { ps.close(); } catch (Exception ex) { /* ex.printStackTrace(); */ } } }
int deleteTemplate() throws Exception { PreparedStatement ps = null; try { ps = con.prepareStatement("DELETE FROM MyDB WHERE Field_Name = 'Field-Value'"); return ps.executeUpdate(); // num rows affected } finally { if (ps != null) try { ps.close(); } catch (Exception ex) { /* ex.printStackTrace(); */ } } }
JDBC Datenbanken befinden sich nach dem Öffnen im AutoCommit
-Modus, d.h. jeder
Update
, Insert
und Delete
wirkt sich unmittelbar
auf den Inhalt der Datenbank aus. Wenn gefordert ist, dass ein kompletter Satz von
Datenbank-Anweisungen entweder durchgeführt, oder im Fehlerfall die Datenbank in den
ursprünglichen Stand zurück versetzt werden soll, müssen diese Anweisungen durch eine
Transaktion geklammert werden.
void myTransaction(Connection con) throws Exception { try { // 1. Einleitung der Transaktion con.setAutoCommit(false); // 2. Ausführung der Transaktion myDatabaseAccess_1(); myDatabaseAccess_2(); // ... myDatabaseAccess_N(); // 3. Abschluß der Transaktion con.commit(); } catch (Exception ex) { // Zurückfahren der Transaktion im Fehlerfall con.rollback(); throw ex; } finally { // Commit-Modos in jedem Fall wieder auf Auto setzen! con.setAutoCommit(true); } }
Voraussetzung ist natürlich, dass die Datenbank Transaktionen unterstützt. Tut sie das
nicht, arbeitet sie in der Regel immer im Modus AutoCommit
, ganz egal,
ob man sie mittels setAutoCommit(...)
auf true
oder
false
einstellt und auch ein commit()
oder rollback()
bewirkt in diesem Fall nichts. Allerdings sauberer ist, zunächst einmal festzustellen,
ob die Datenbank überhaupt Transaktionen unterstützt und den Programmcode dann daraufhin
abzustimmen:
boolean supportsTransactions(Connection con) throws SQLException { return con.getMetaData().supportsTransactions(); }
Copyright © 2003 Wöhrmann Softwareentwicklung - Höhenkirchen-Siegertsbrunn - Landkreis München