Objets ResultSet multiples ouverts simultanément pour des instructions SELECT identiques

L'ouverture simultanée de plusieurs objets ResultSet pour des instructions SELECT identiques peut causer des problèmes sous certaines conditions lorsque votre application non-pureQuery exécute des instructions SQL en mode statique.
Ces conditions sont les suivantes :
  • Les objets ResultSet sont ouverts par une connexion unique.
  • Les objets ResultSet sont retournés par des instructions SELECT identiques dotées d'attributs de curseur identiques.
  • Les objets ResultSet restent ouverts simultanément.
  • Les objets ResultSet sont modifiés par des instructions UPDATE ou DELETE contenant la clause WHERE CURRENT OF.

Par exemple, imaginons le code suivant :

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());

Si les instructions SQL sont exécutées en mode dynamique, ce code ne comporte pas d'ambiguïtés. Toutefois, si elles sont exécutées en mode statique et que les objets ResultSet sont ouverts avec la même connexion, un problème survient. Lorsque pureQuery capture les instructions SQL d'une application non-pureQuery, il capture des instructions identiques une seule fois. Une fois les instructions SQL capturées par pureQuery dans cet exemple, le fichier pureQueryXML contient une instance de SELECT * FROM SCH1.TBL1. Si pureQuery attribue le nom DB_PDQ_SPC7 au curseur, le fichier pureQueryXML contient également une instance de DELETE FROM SCH1.TBL1 WHERE CURRENT OF DB_PDQ_SPC7.

Lors de l'exécution, si vous utilisez uniquement le nom du curseur dans la clause WHERE CURRENT OF, pureQuery ne peut pas déterminer l'objet ResultSet sur lequel le curseur de l'instruction DELETE agit.

Les mêmes ambiguïtés peuvent être relevées dans des situations moins évidentes. Par exemple, les instructions SELECT peuvent se trouver dans des méthodes retournant des objets ResultSet et les instructions UPDATE ou DELETE WHERE CURRENT OF peuvent se trouver dans des méthodes recevant des objets ResultSet comme paramètres d'entrée.

Le problème peut ne pas être évident dans un code source d'application. Voilà pourquoi pureQuery consigne un avertissement lorsqu'il détecte plusieurs objets ResultSet actuellement ouverts pour une seule instruction SELECT.

Techniques de contournement du problème

Voici des techniques permettant de lever toute ambiguïté.

N'utilisez pas la clause WHERE CURRENT OF
Utilisez plutôt les méthodes updateRow(), deleteRow() et insertRow(). Cette méthode est plus orientée objet que la spécification d'instructions utilisant la clause WHERE CURRENT OF.
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(); 
Si vous devez utiliser la clause WHERE CURRENT OF dans une instruction UPDATE ou DELETE, vous pouvez intégrer l'appel à ResultSet.getCursorName() lorsque vous préparez ou exécutez l'instruction, comme dans l'exemple suivant :
PreparedStatement pStmt = jdbcCon.prepareStatement(
	"DELETE FROM SCH1.TBL1 WHERE CURRENT OF " +
	rs2.getCursorName());
Lors de l'exécution, pureQuery peut associer la méthode getCursorName() à l'instruction UPDATE ou DELETE et, par conséquent, associer l'objet ResultSet correct à l'instruction. Cette association est garantie uniquement lorsque la méthode getCursorName() apparaît dans l'un de ces deux points :
  • Avec l'instruction SQL dans l'appel de méthode créant une instruction préparée
  • Dans les méthodes execute() ou executeUpdate() d'un objet Statement
N'utilisez jamais une connexion pour manipuler plusieurs objets ResultSet ouverts simultanément pour des instructions SELECT identiques si votre application manipule ces objets avec des instructions UPDATE ou DELETE contenant des clauses WHERE CURRENT OF
Le code situé au début de cette rubrique fonctionne si les objets ResultSet sont ouverts via des connexions distinctes.

Propriété autorisant l'exécution d'instructions SQL SELECT identiques sur DB2 for z/OS

Si vous devez exécuter des instructions SQL SELECT statiques identiques dans DB2 for z/OS et ouvrir plusieurs objets ResultSet identiques, commencez par définir la propriété IBM® pour JDBC et SQLJ db2.jcc.allowSqljDuplicateStaticQueries sur YES ou TRUE.


Commentaires