JDBC−Treiber
Middleware−Spezialist OpenLink bietet universellen
Treiber für die meisten DBMS (inkl. PostgreSQL) und
ODBC−Datenquellen.
JDBC−Treiber kontaktiert Request Broker.
Request Broker vermittelt Zugriff zur Datenbank
Sun Microsystems bietet mit JDBC eine JDBC−ODBC−
Brücke für Zugriff auf ODBC−Datenquellen.
Treiber−Klasse: sun.jdbc.odbc.JdbcOdbcDriver
Weitere JDBC−Treiber:
http://industry.java.sun.com/products/jdbc/drivers
Web−Anwendung zur Treiberauswahl
Web−Anwendungen mit Java
401
Datenbankverbindung aufbauen
Connection con =
DriverManager.getConnection
("jdbc:postgresql://mark:5712/eshop",
"user", "password");
JDBC−URL identifiziert Datenbank.
Aufbau: jdbc:subprotocol:subname
Treibermanager übergibt JDBC−URL der Reihe nach
an registrierte Treiber.
Driver.acceptsURL(String url)
Liefert true, falls der Treiber das Subprotocol erkennt.
Beispiel: JDBC−ODBC−Bridge erkennt
jdbc:odbc:mydb;UID=me;PWD=secret
Web−Anwendungen mit Java
402
Connection
Ergebnis von DriverManager.getConnection()
ist eine Connection (oder eine SQLException).
Verbindung zur Datenbank
Connection ist teure Ressource:
Aufbau der Verbindung kostet viel Zeit.
Anzahl gleichzeitiger Verbindungen häufig beschränkt.
Voreinstellung bei PostgreSQL: max. 32 Verbindungen
Wichtigste Aufgaben:
Erzeugen von Statement−Objekten
Beschreibungen von Datenbank und DBMS erfragen
Transaktionen handhaben
Web−Anwendungen mit Java
403
Statement
Statement stmt = con.createStatement();
Wird immer aus bestehender Connection erzeugt
Ausführen einer SQL−Anweisung über die Connection.
Mehrere parallele Statements pro Connection möglich
SELECT−Anweisung ausführen:
ResultSet rs =
stmt.executeQuery("SELECT * FROM kunden");
Daten ändern:
int updates =
stmt.executeUpdate("DELETE FROM kunden ...");
Web−Anwendungen mit Java
404
ResultSet: Zeilendurchlauf
ResultSet rs =
stmt.executeQuery("SELECT * FROM kunden");
Ergebnis einer Selektionsanweisung: Tabelle
Wird aus Statement erzeugt.
ResultSet enthält einen Datensatz−Zeiger (Cursor)
zum Durchlauf der Tabelle.
Voreinstellung: sequentiell und lesend
JDBC 2: nichtsequentielle und aktualisierbare ResultSets
Zeiger steht initial vor der ersten Tabellenzeile.
ResultSet.next() positioniert zur nächsten Zeile.
Liefert false, falls bereits auf letzter Zeile
Web−Anwendungen mit Java
405
ResultSet: Attribute lesen
Spaltenwerte (Attribute) einer Zeile mit getXXX()−
Methoden lesen
Treiber konvertiert Daten, falls möglich
Beispiel: Lesen einer ganzen Zahl in Spalte »anzahl«:
Effizientere Methode, falls Spaltenindex bekannt:
int n = rs.getInt("anzahl");
int n = rs.getInt(4);
Spaltenindex zum Spaltennamen finden
int findColumn(String columnName)
Strategie: Spaltenindex einmalig ermitteln und merken,
Werte danach immer über den Index abrufen.
Web−Anwendungen mit Java
406
ResultSet: Attribute lesen
Zahlreiche weitere Methoden
getArray, getAsciiStream, getBigDecimal,
getBinaryStream, getBlob, getBoolean,
getByte, getBytes, getCharacterStream,
getClob, getDate, getDouble, getFloat,
getInt, getLong, getObject, getRef,
getShort, getString, getTime, getTimestamp
Web−Anwendungen mit Java
407
ResultSet: Attribute lesen
Methode getObject
Liest jeden beliebigen SQL−Datentyp
Liefert Ergebnis als entsprechenden Java−Typ
Nullwerte
Temperaturen
Datum Temperatur
24.12.2001
2
25.12.2001
0
26.12.2001
27.12.2001
−2
Spalte kann leere Zellen
enthalten (Nullwert, SQL−NULL).
Bei leerer Zelle liefert getInt()
ebenfalls das Ergebnis 0.
Unterscheidung zu echter 0 möglich durch wasNull()
true, falls zuletzt mit getXXX() gelesene Zelle
SQL−NULL enthielt
false sonst
Web−Anwendungen mit Java
408
ResultSet: Ressourcen freigeben
Nach Bearbeitung ResultSet schließen
void close()
Gibt Ressourcen frei
Ausführen einer weiteren Anweisung mit demselben
Statement schließt das ResultSet implizit.
Web−Anwendungen mit Java
409
ResultSet: positionieren und ändern
Statement createStatement(int
resultSetType, int resultSetConcurrency)
Parameter (ResultSet−Konstanten) ermöglichen
beliebiges Positionieren (»Scrolling«) und Ändern der
Datensätze.
TYPE_FORWARD_ONLY: sequentieller Durchlauf
TYPE_SCROLL_INSENSITIVE: positionierbar,
Änderungen an Datenbank werden nicht bemerkt.
TYPE_SCROLL_SENSITIVE: positionierbar, Änderungen
an Datenbank werden bemerkt.
CONCUR_READ_ONLY: nur lesen
CONCUR_UPDATABLE: Änderungen möglich
Web−Anwendungen mit Java
410
ResultSet: positionieren
void beforeFirst()
boolean first()
Positioniert auf den ersten Satz.
boolean last()
Positioniert vor den ersten Satz.
Positioniert auf den letzten Satz
void afterLast()
Positioniert hinter den letzten Satz.
Web−Anwendungen mit Java
411
ResultSet: positionieren
boolean absolute(int pos)
boolean relative(int rows)
Positioniert relativ zum aktuellen Satz vorwärts (rows
positiv) oder rückwärts (rows negativ).
boolean next()
Positioniert relativ zum Anfang (pos positiv) oder relativ
zum Ende (pos negativ).
Positioniert auf den nächsten Satz.
boolean previous()
Positioniert auf den vorigen Satz.
Web−Anwendungen mit Java
412
ResultSet: positionieren
int getRow()
boolean isBeforeFirst()
Liefert true, falls auf dem ersten Satz.
boolean isLast()
Liefert true, falls vor dem ersten Satz.
boolean isFirst()
Liefert aktuelle Satznummer.
Liefert true, falls auf dem letzten Satz.
boolean isAfterLast()
Liefert true, falls hinter dem letzten Satz.
Web−Anwendungen mit Java
413
ResultSet: Datensatz ändern
Methoden updateXXX() ändern Werte in aktueller
Zeile.
rs.absolute(5);
rs.updateString("Name", "Klute");
rs.updateInt(2, 42);
rs.updateNull(3);
rs.updateRow();
void updateRow()
void cancelRowUpdates()
Schreibt geänderte Zeile in die Datenbank.
Macht Änderungen rückgängig − vor updateRow().
void deleteRow()
Löscht aktuelle Zeile aus ResultSet und Datenbank
Web−Anwendungen mit Java
414
ResultSet: Datensatz einfügen
Einfügezeile: im ResultSet, nicht in der Datenbank
rs.moveToInsertRow();
rs.updateString("Name", "Klute");
rs.updateInt(2, 42);
rs.insertRow();
rs.moveToCurrentRow();
void moveToInsertRow()
void insertRow()
Positioniert auf die Einfügezeile
Schreibt Einfügezeile in ResultSet und Datenbank
void moveToCurrentRow()
Positioniert von der Einfügezeile auf die aktuelle
Zeile im ResultSet
Web−Anwendungen mit Java
415
ResultSet: Änderungen erkennen
Datenbank kann sich jederzeit ändern...
...durch andere Benutzer,
...durch eigene parallele Anweisungen.
Ziel: beim Lesen des ResultSets Änderungen
erkennen
Voraussetzung:
Statement mit ResultSet.TYPE_SCROLL_SENSITIVE
erzeugen.
Mehraufwand kostet Performance.
Implementationsabhängig
Web−Anwendungen mit Java
416
ResultSet: Änderungen erkennen
void refreshRow()
boolean rowDeleted()
Liefert true, falls aktuelle Zeile in der Datenbank
gelöscht wurde.
boolean rowInserted()
Liest aktuelle Zeile neu aus der Datenbank.
Liefert true, falls aktuelle Zeile »Einfügung hatte«.
boolean rowUpdated()
Liefert true, falls aktuelle Zeile in Datenbank geändert
wurde.
Web−Anwendungen mit Java
417
PostgreSQL und JDBC 2
Mit dem PostgreSQL beigegebenen JDBC−Treiber
ist nicht alles möglich, was JDBC 2 für ResultSets
vorsieht.
TYPE_FORWARD_ONLY: Ja
TYPE_SCROLL_INSENSITIVE: Ja
TYPE_SCROLL_SENSITIVE: Nein
CONCUR_READ_ONLY: Ja
CONCUR_UPDATABLE: Nein
Web−Anwendungen mit Java
418
Daten ändern mit UPDATE
SQL−Anweisung UPDATE ändert bestehende
Datensätze.
Viele Datensätze durch einen einzigen Befehl ändern
Daten ändern auch ohne modifizierbare ResultSets
Beispiele:
UPDATE artikel SET preis = 100;
UPDATE artikel SET preis = preis * 1.05
where id = 538;
UPDATE artikel SET preis = preis * 1.05
where preis < 1000;
Web−Anwendungen mit Java
419
Daten löschen mit DELETE
SQL−Anweisung DELETE löscht bestehende
Datensätze.
Viele Datensätze durch einen einzigen Befehl löschen
Daten löschen ohne modifizierbare ResultSets
Beispiele:
DELETE FROM artikel WHERE id = 538;
DELETE FROM artikel WHERE preis < 100;
DELETE FROM artikel WHERE NOT id IN
(artikel FROM bestellungen);
Löscht alle Artikel, die nie bestellt wurden
Web−Anwendungen mit Java
420
ResultSet: Treiberhinweise
void setFetchDirection(int direction)
Optimierungshinweis an den JDBC−Treiber: In welcher
Richtung liest die Anwendung das ResultSet?
FETCH_FORWARD, FETCH_REVERSE oder
FETCH_UNKNOWN
int getFetchDirection()
void setFetchSize(int rows)
JDBC−Treiber muß nicht alle Zeilen sofort aus der
Datenbank holen.
Optimierungshinweis an den JDBC−Treiber:
Wieviel Zeilen am Stück holen?
int getFetchSize()
Web−Anwendungen mit Java
421
ResultSet: Diverses
Statement getStatement()
int getType()
TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE
oder TYPE_SCROLL_SENSITIVE
int getConcurrency()
Statement, das dieses ResultSet erzeugt hat
CONCUR_READ_ONLY oder CONCUR_UPDATABLE
String getCursorName()
Zum Ändern oder Löschen der aktuellen Zeile
UPDATE table SET n = 42 WHERE CURRENT OF cursor
DELETE FROM table WHERE CURRENT OF cursor
Web−Anwendungen mit Java
422
ResultSet: Metadaten
Informationen über das ResultSet
public ResultSetMetaData getMetaData()
Anzahl der Spalten
Spaltentyp, −name und −titel
Kann man Spalte nur lesen oder auch schreiben?
Entsteht Spaltenwert durch automatische Numerierung
(Sequenz)?
Läßt sich Spalte in WHERE−Klausel verwenden?
Darf Spalte Nullwert enthalten?
usw.
Web−Anwendungen mit Java
423
Statement: Daten ändern
ResultSet executeQuery(String) führt
SELECT−Anweisung aus.
int Statement.executeUpdate(String) führt
INSERT−, UPDATE− oder DELETE−Anweisung aus.
Liefert Anzahl betroffener Zeilen (»Update count«).
Auch für sonstige Befehle (»CREATE ...«) geeignet.
boolean execute(String) führt beliebige SQL−
Anweisung aus.
Liefert true, falls Ergebnis ein ResultSet ist
⇒ ResultSet rs = stmt.getResultSet();
Liefert false, falls Ergebnis ein Update count ist
⇒ int count = stmt.getUpdateCount();
Web−Anwendungen mit Java
424
Statement: vorbereitete Anweisungen
Aufbau der Anweisung fest, Parameter wechseln
Beispiel
PreparedStatement pstmt = con.prepareStatement
("INSERT INTO temperaturen VALUES (?, ?)");
pstmt.setString(1, "{d 2001−12−24}");
pstmt.setInt(2, 2);
pstmt.executeUpdate();
pstmt.setString(1, "{d 2001−12−25}");
pstmt.setInt(2, 0);
pstmt.executeUpdate();
pstmt.setString(1, "{d 2001−12−26}");
pstmt.setNull(2, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setString(1, "{d 2001−12−27}");
pstmt.setInt(2, −2);
pstmt.executeUpdate();
Läßt sich auch für Queries nutzen.
Web−Anwendungen mit Java
425
Statement: Stapelverarbeitung
Mehrere SQL−Anweisungen in einem Rutsch
ausführen (optionale JDBC−Operation)
Schritt 1: Anweisungen sammeln
Schritt 2: Stapel ausführen
void clearBatch()
void addBatch(String sql)
Stapel löschen
SQL−Anweisung zum Stapel hinzufügen
int[] executeBatch()
Stapel ausführen
Ergebniscode pro Anweisung
Web−Anwendungen mit Java
426
DBMS−Metadaten
Connection−Methode
public DatabaseMetaData getMetadata()
Methoden liefern Informationen über das DBMS, SQL−
Features, JDBC−Treiber, Tabellen,
Datenbankprozeduren u.v.a.m.
Nicht jeder JDBC−Treiber unterstützt jede Methode
von DatabaseMetaData.
Richtig: SQLException
Falsch: Fehlende oder falsche Informationen
Web−Anwendungen mit Java
427
DBMS−Metadaten
int−Methoden: beschreiben technische
Einschränkungen
Maximale Anzahl von Spalten je Tabelle
Größte Länge einer SQL−Anweisung
usw.
boolean−Methoden: Fähigkeit verfügbar oder nicht.
Beispiele:
boolean supportsANSI92EntryLevelSQL()
boolean supportsANSI92FullSQL()
Ergebnisse häufig als ResultSet
Beispiel: unterstützte Datentypen mittels Servlet
anzeigen
Web−Anwendungen mit Java
428
Beispiel: DBMS−Metadaten anzeigen
Web−Anwendungen mit Java
429
Beispiel: DBMS−Metadaten anzeigen
Web−Anwendungen mit Java
430
Beispiel: DBMS−Metadaten anzeigen
package de.rainer_klute.jdbc;
import
import
import
import
java.io.*;
java.sql.*;
javax.servlet.*;
javax.servlet.http.*;
public class DBInfo extends HttpServlet
{
/**
* <p>Initializes the servlet by setting the
* jdbc.drivers system property from the
* "databaseDrivers" servlet context init
* parameter.</p>
*
* <p><strong>FIXME:</strong> The method should
* append only those driver class names that are not
* already in the "jdbc.drivers" property.</p>
*/
public void init(ServletConfig config)
throws ServletException
Web−Anwendungen mit Java
431
Beispiel: DBMS−Metadaten anzeigen
{
}
final String driverProp = "jdbc.drivers";
super.init(config);
StringBuffer newDrivers = new StringBuffer();
String oldDrivers =
System.getProperty(driverProp);
if (oldDrivers != null)
{
newDrivers.append(oldDrivers);
newDrivers.append(’:’);
}
String s;
if ((s = config.getServletContext().
getInitParameter
("databaseDrivers")) != null)
newDrivers.append(s);
System.setProperty
(driverProp, newDrivers.toString());
Web−Anwendungen mit Java
432
Beispiel: DBMS−Metadaten anzeigen
public void doGet(HttpServletRequest req,
HttpServletResponse resp)
{
PrintWriter out = null;
try
{
out = resp.getWriter();
doGetLocal(req, resp, out);
}
catch (SQLException ex)
{
out.println("<pre>");
ex.printStackTrace(out);
out.println("</pre>");
}
catch (IOException ex)
{
out.println("<pre>");
ex.printStackTrace(out);
out.println("</pre>");
}
}
Web−Anwendungen mit Java
433
Beispiel: DBMS−Metadaten anzeigen
private void doGetLocal(HttpServletRequest req,
HttpServletResponse resp,
PrintWriter p)
throws SQLException
{
// Parameter für Connection ermitteln:
ServletContext sc = getServletContext();
String url =
sc.getInitParameter("databaseURL");
String user =
sc.getInitParameter("databaseUser");
String password =
sc.getInitParameter("databasePassword");
// Datenbankverbindung aufbauen:
Connection con = DriverManager.getConnection
(url, user, password);
DatabaseMetaData dbmd = con.getMetaData();
Web−Anwendungen mit Java
434
Beispiel: DBMS−Metadaten anzeigen
p.println("<div>");
p.println("<p>Database system: " +
dbmd.getDatabaseProductName() +
" " +
dbmd.getDatabaseProductVersion() +
"</p>");
p.println("<p>JDBC driver: " +
dbmd.getDriverName() + " " +
dbmd.getDriverVersion() + "</p>");
ResultSet rs;
/* Schemas */
p.println("<p>Schemas:</p>");
rs = dbmd.getSchemas();
Util.printAsHTML(p, rs);
/* Catalogs */
p.println("<p>Catalogs:</p>");
rs = dbmd.getCatalogs();
Util.printAsHTML(p, rs);
Web−Anwendungen mit Java
435
Beispiel: DBMS−Metadaten anzeigen
/* TableTypes */
p.println("<p>Table types:</p>");
rs = dbmd.getTableTypes();
Util.printAsHTML(p, rs);
/* Tables */
p.println("<p>Tables:</p>");
rs = dbmd.getTables(null, null, null, null);
Util.printAsHTML(p, rs);
/* Data types */
p.println("<p>Data types supported by " +
"this database system:</p>");
rs = dbmd.getTypeInfo();
Util.printAsHTML(p, rs);
// Datenbankverbindung schließen:
con.close();
}
}
p.println("</div>");
Web−Anwendungen mit Java
436
Beispiel: Klasse Util
package de.rainer_klute.jdbc;
import java.io.*;
import java.sql.*;
import java.util.*;
/**
* <p>Contains static methods for dealing with JDBC
* objects.</p>
*
* @author Rainer Klute &lt;klute@rainer−klute.de&gt;
*/
public class Util
{
Web−Anwendungen mit Java
437
Beispiel: Klasse Util
/**
* <p>Prints the contents of a {@link ResultSet} to
* a {@link PrintWriter} as an HTML table with cell
* borders.</p>
*
* @param p The HTML table is rendered to this
* {@link PrintWriter}
* @param re The {@link ResultSet} to print
*
* @see #printAsHTML(PrintWriter, ResultSet, Map)
*/
public static void printAsHTML(PrintWriter p,
ResultSet rs)
throws SQLException
{
Map m = new HashMap(1);
m.put("border", "1");
printAsHTML(p, rs, m);
}
Web−Anwendungen mit Java
438
Beispiel: Klasse Util
/**
* <p>Prints the contents of a {@link ResultSet} to
* a {@link PrintWriter} as an HTML table.</p>
*
* @param p The HTML table is rendered to this
* {@link PrintWriter}
* @param re The {@link ResultSet} to print
* @param tableAttr Attributes to use for the
* HTML table
*
* @see #printAsHTML(PrintWriter, ResultSet)
*/
public static void printAsHTML(PrintWriter p,
ResultSet rs,
Map tableAttr)
throws SQLException
{
p.print("<table");
/* Print table attributes */
for (Iterator i = tableAttr.keySet().iterator();
i.hasNext();)
Web−Anwendungen mit Java
439
Beispiel: Klasse Util
{
String attr = (String) i.next();
p.print(’ ’);
p.print(attr);
p.print("=\"");
p.print((String) tableAttr.get(attr));
p.print(’\"’);
}
p.println(">");
/* Get number of columns */
ResultSetMetaData rsmd = rs.getMetaData();
int columns = rsmd.getColumnCount();
/* Get column names from metadata and print them
* to the first table row. */
p.print("<tr>");
for (int i = 1; i <= columns; i++)
p.print("<th><p>" + rsmd.getColumnName(i) +
"</p></th>");
p.println("</tr>");
Web−Anwendungen mit Java
440
Beispiel: Klasse Util
}
/* Print result set lines. */
while (rs.next())
{
p.print("<tr>");
for (int i = 1; i <= columns; i++)
{
/* Print cell contents. */
String s;
Object o;
if ((o = rs.getObject(i)) != null)
s = o.toString();
else
s = "&nbsp;";
p.print("<td><p>" + s + "</p></td>");
}
p.println("</tr>");
}
p.println("</table>");
}
Web−Anwendungen mit Java
441
Transaktionen
Zusammengehörende Datenbankoperationen
Entweder alle ausführen oder keine
Beispiel: Überweisung
int amount = 100;
/* Transaktion einleiten. */
con.setAutoCommit(false);
fromAccount(con, 1, amount);
if (Math.random() > 0.5)
throw new RuntimeException("Crash");
toAccount(con, 2, amount);
/* Transaktion abschließen: Ergebnisse endgültig
* in Datenbank schreiben. */
con.commit();
con.setAutoCommit(true);
Web−Anwendungen mit Java
442
Transaktionen
/*
* <p>Lastschrift</p>
*/
private static void fromAccount
(Connection c, int account, int amount)
throws SQLException
{
/* Alten Kontostand holen. */
PreparedStatement s;
s = c.prepareStatement
("SELECT saldo FROM konten WHERE konto = ?");
s.setInt(1, account);
ResultSet rs = s.executeQuery();
rs.next();
int balance = rs.getInt(1);
/* Neuen Kontostand berechnen. */
balance −= amount;
Web−Anwendungen mit Java
443
Transaktionen
}
/* Neuen Kontostand in Datenbank speichern. */
s = c.prepareStatement
("UPDATE konten SET saldo = ? " +
"WHERE konto = ?");
s.setInt(1, balance);
s.setInt(2, account);
s.executeUpdate();
s.close();
/*
* <p>Gutschrift</p>
*/
private static void toAccount
(Connection c, int account, int amount)
throws SQLException
{
fromAccount(c, account, −amount);
}
Web−Anwendungen mit Java
444
Transaktionen
void setAutoCommit(boolean autoCommit)
true: Jede SQL−Anweisung ist separate Transaktion.
false: SQL−Anweisungen sind zu Transaktionen
gruppiert.
boolean getAutoCommit()
void commit()
Zustand erfragen
Transaktion abschließen: Änderungen endgültig in
Datenbank schreiben
void rollback()
Transaktion zurücksetzen: Änderungen verwerfen
Web−Anwendungen mit Java
445
Transaktionen voreinander schützen
void setTransactionIsolation(int level)
Legt fest, wie stark Transaktionen voneinander
abgeschottet sind.
Sind Änderungen während einer Transaktion T1 bereits
in einer Transaktion T2 sichtbar?
Daumenregel: geringe Abschottung = hoher Durchsatz
int getTransactionIsolation()
Aktuellen Wert abfragen
Web−Anwendungen mit Java
446
Transaktionen voreinander schützen
Schmutzlesen (»dirty read«):
Einmallesen (»non−repeatable read«)
T1 schreibt Satz, T2 liest Satz, T1 bricht ab
⇒ Satz ist »dirty«.
T1 liest Satz, T2 ändert Satz, T1 liest Satz noch einmal
⇒ Satz ist bei jedem Lesen anders.
Phantomlesen (»phantom read«)
T1 selektiert Relation mit Selektionsbedingung B, T2 fügt
Satz ein, der B erfüllt, T1 selektiert Relation mit B noch
einmal
⇒ Relation enthält zusätzlichen »Phantomsatz«.
Web−Anwendungen mit Java
447
Transaktionen voreinander schützen
TRANSACTION_READ_UNCOMMITTED
Erlaubt Schmutzlesen, Einmallesen und Phantomlesen
TRANSACTION_READ_COMMITTED
Verhindert Schmutzlesen
Erlaubt Einmallesen und Phantomlesen
TRANSACTION_REPEATABLE_READ
Verhindert Schmutzlesen und Einmallesen
Erlaubt Phantomlesen
TRANSACTION_SERIALIZABLE
Verhindert Schmutzlesen, Einmallesen und
Phantomlesen
Web−Anwendungen mit Java
448
Parallele SQL−Anweisungen
Datenbankoperationen benötigen viel Zeit
1
... datenbankunabhängige Aktivitäten erledigen
In separatem Thread ausführen und in der Wartezeit...
Benutzeroberfläche aktualisieren usw.
... weitere Datenbankoperation parallel ausführen
C
C
C
S
S
S
RS
RS
RS
RS
Web−Anwendungen mit Java
449
C
C
S
S
S
RS
RS
RS
Parallele Anweisungen: Varianten
Paralleles ResultSet erzeugen
Statement für weitere SQL−Anweisung nutzen
Nicht möglich, da Statement.execute() das
geöffnete ResultSet schließt
Paralleles Statement erzeugen
Connection für weiteres Statement nutzen
JDBC−Treiber synchronisiert, falls nötig
Güte der Synchronisierung abhängig von DBMS und Treiber
Parallele Connection erzeugen