Mehrere gleichzeitig für identische SELECT-Anweisungen geöffnete ResultSet-Objekte

Wenn mehrere ResultSet-Objekte gleichzeitig für identische SELECT-Anweisungen geöffnet bleiben, kann dies unter bestimmten Bedingungen zu Problemen führen, wenn Ihre Nicht-pureQuery-API-Anwendung SQL statisch ausführt.
Diese Bedingungen sind:
  • Die ResultSet-Objekte wurden von einer einzelnen Verbindung geöffnet.
  • Die ResultSet-Objekte wurden von identischen SELECT-Anweisungen mit identischen Cursorattributen zurückgegeben.
  • Die ResultSet-Objekte bleiben gleichzeitig geöffnet.
  • Die ResultSet-Objekte werden von UPDATE- oder DELETE-Anweisungen geändert, die die Klausel WHERE CURRENT OF enthalten.

Es liegt beispielsweise folgender Code vor:

ResultSet rs1, rs2;

Statement stmt1 = jdbcCon.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE);
rs1 = stmt1.executeQuery("SELECT * FROM SCH1.TBL1");
rs1.next();

Statement stmt2 = jdbcCon.createStatement(TYPE_FORWARD_ONLY, CONCUR_UPDATABLE);
rs2 = stmt2.executeQuery("SELECT * FROM SCH1.TBL1");
  rs2.next();

PreparedStatement pStmt = jdbcCon.prepareStatement(
	"DELETE FROM SCH1.TBL1 WHERE CURRENT OF " +
	rs2.getCursorName());

Wenn die SQL-Anweisungen dynamisch ausgeführt werden, stellt dieser Code keine Mehrdeutigkeit dar. Wenn sie jedoch statisch ausgeführt werden und die ResultSet-Objekte mit derselben Verbindung geöffnet wurden, tritt ein Problem auf. Wenn pureQuery SQL-Anweisungen für eine Nicht-pureQuery-API-Anwendung erfasst, werden identische Anweisungen nur einmal erfasst. Nachdem pureQuery die SQL-Anweisungen in diesem Beispiel erfasst, enthält die pureQueryXML-Datei eine Instanz von SELECT * FROM SCH1.TBL1. Wenn pureQuery dem Cursor den Namen DB_PDQ_SPC7 zuordnet, enthält die pureQueryXML-Datei auch eine Instanz von DELETE FROM SCH1.TBL1 WHERE CURRENT OF DB_PDQ_SPC7.

Wenn nur der Cursorname in der Klausel WHERE CURRENT OF während der Ausführung verwendet wird, kann pureQuery nicht feststellen, auf welche der beiden ResultSet-Objekte sich der Cursor in der Anweisung DELETE auswirkt.

Dieselbe Mehrdeutigkeit kann in weniger offensichtlichen Situationen auftreten. Beispielsweise können sich die SELECT-Anweisungen in Methoden befinden, die ResultSet-Objekte zurückgeben, und die UPDATE- oder DELETE WHERE CURRENT OF-Anweisungen können sich in Methoden befinden, die ResultSet-Objekte als Eingabeparameter empfangen.

Das Problem kann auch im Quellcode einer Anwendung nicht offensichtlich sein. Aus diesem Grund protokolliert pureQuery eine Warnung, wenn festgestellt wird, dass zu einem Zeitpunkt mehrere ResultSet-Objekte für eine einzige Anweisung SELECT geöffnet sind.

Verfahren zur Vermeidung des Problems

Mit den folgenden Verfahren können Sie versuchen, diese Mehrdeutigkeit zu beheben.

Verwendung der Klausel WHERE CURRENT OF vermeiden
Verwenden Sie stattdessen die Methoden updateRow(), deleteRow() und insertRow(). Diese Lösung ist objektorientierter als die Angabe von Anweisungen, die die Klausel WHERE CURRENT OF verwenden.
Statement stmt1 = jdbcCon.createStatement(TYPE_FORWARD_ONLY,CONCUR_UPDATABLE);
rs1 = stmt.executeQuery("SELECT * FROM SCH1.TBL1");
rs1.next();

Statement stmt2 = jdbcCon.createStatement(TYPE_FORWARD_ONLY,CONCUR_UPDATABLE);
rs2 = stmt.executeQuery("SELECT * FROM SCH1.TBL1"); 
rs2.next();

rs2.deleteRow(); 
Wenn Sie die Klausel WHERE CURRENT OF in einer Anweisung UPDATE oder DELETE verwenden müssen, können Sie den Aufruf von ResultSet.getCursorName() bei der Vorbereitung oder Ausführung der Anweisung einbetten, wie im folgenden Beispiel gezeigt:
PreparedStatement pStmt = jdbcCon.prepareStatement(
	"DELETE FROM SCH1.TBL1 WHERE CURRENT OF " +
	rs2.getCursorName());
Während der Ausführung kann pureQuery die Methode getCursorName() der Anweisung UPDATE oder DELETE zuordnen und ordnet daher der Anweisung das richtige Objekt ResultSet zu. Diese Zuordnung wird jedoch nur sichergestellt, wenn sich die Methode getCursorName() an einer der beiden folgenden Positionen befindet:
  • Zusammen mit der SQL-Anweisung im Methodenaufruf, der ein Objekt PreparedStatement erstellt
  • In den Methoden execute() oder executeUpdate() eines Anweisungsobjekts
Nie eine Verbindung verwenden, um mehrere ResultSet-Objekte zu bearbeiten, die gleichzeitig für identische SELECT-Anweisungen geöffnet sind, wenn Ihre Anweisung diese Objekte mit UPDATE- oder DELETE-Anweisungen bearbeitet, die WHERE CURRENT OF-Klauseln enthalten
Der Code zu Beginn dieses Themas funktioniert, wenn die ResultSet-Objekte von separaten Verbindungen geöffnet werden.

Eigenschaft, die die Ausführung identischer SQL-Anweisungen SELECT unter DB2 for z/OS ermöglicht

Wenn Sie identische statische SQL-Anweisungen SELECT für DB2 for z/OS ausführen müssen und mehrere identische ResultSet-Objekte öffnen müssen, müssen Sie zuerst die IBM® Data Server Driver für JDBC und SQLJ-Eigenschaft db2.jcc.allowSqljDuplicateStaticQueries auf YES oder TRUE setzen.


Feedback