web-dev-qa-db-fra.com

PreparedStatement.addBatch () peut-il être utilisé pour les requêtes SELECT?

Imaginez que j'ai 100 requêtes SELECT qui diffèrent par une entrée. Un PreparedStatement peut être utilisé pour la valeur.

Toute la documentation que je vois sur le Web concerne l'insertion/la mise à jour/la suppression par lots. Je n'ai jamais vu de lots utilisés pour certaines instructions.

Cela peut-il être fait? Si c'est le cas, veuillez m'aider lorsque l'exemple de code ci-dessous.

Je suppose que cela peut être fait en utilisant une clause "IN", mais je préférerais utiliser des instructions de sélection par lots.

Exemple de code:

 public void run (Connection db_conn, List value_list) {
 String sql = "SELECT * FROM DATA_TABLE WHERE ATTR =?"; 
 PreparedStatement pstmt = db_conn.prepareStatement (sql); 
 pour (Valeur chaîne: liste_valeurs) {
 pstmt.clearParameters (); 
 pstmt.setObject (1, valeur); 
 pstmt.addBatch (); 
} 
 // Comment appeler ici? 
 Int [] result_array = pstmt.executeBatch () 
 While (pstmt.getMoreResults ()) {
 ResultSet result_set = pstmt.getResultSet (); 
 // fonctionne ici 
} 
} 

Je suppose que cela peut également être un comportement dépendant du conducteur. J'écris des requêtes sur la base de données IBM AS/400 DB2 à l'aide de leur pilote JDBC.

23
kevinarpe

Voir le Java :

Cette liste peut contenir des instructions pour mettre à jour, insérer ou supprimer une ligne; et il peut également contenir des instructions DDL telles que CREATE TABLE et DROP TABLE. Il ne peut cependant pas contenir une instruction qui produirait un objet ResultSet, tel qu'une instruction SELECT. En d'autres termes, la liste ne peut contenir que des instructions qui produisent un nombre de mises à jour.

La liste, qui est associée à un objet Statement lors de sa création, est initialement vide. Vous pouvez ajouter des commandes SQL à cette liste avec la méthode addBatch.

48
user207421

JDBC ne permet pas de créer des requêtes SELECT par lots, ce qui, à mon avis, est une limitation frustrante, d'autant plus que les instructions préparées ne vous permettent pas de spécifier un nombre variable d'arguments, comme une IN (...) clause.

L'article de JavaRanch, F.J, renvoie à suggère de simuler le traitement par lots en créant une série de requêtes de taille fixe et en joignant leurs résultats, ce qui me semble une solution lourde et sous-optimale; vous devez maintenant construire et traiter manuellement plusieurs requêtes et frapper la base de données plusieurs fois. Si les nombres choisis pour les lots définis manuellement sont médiocres, vous pourriez finir par frapper la base de données plusieurs fois juste pour répondre à une simple requête.

Au lieu de cela, j'ai commencé à construire dynamiquement des objets PreparedStatement avec le nombre de champs dont j'ai besoin. Cela signifie que nous créons potentiellement un plus grand nombre de PreparedStatement que nous le ferions avec le batch manuel, mais nous limitons la fréquence à laquelle nous frappons la base de données et simplifions notre implémentation, deux points que je considère comme des problèmes plus importants.

/**
 * Use this method to create batch-able queries, e.g:
 * "SELECT * FROM t WHERE x IN (?, ?, ?, ?)"
 * Can be built as:
 * "SELECT * FROM t where x IN ("+getLineOfQs(4)+")"
 */
public static String getLineOfQs(int num) {
  // Joiner and Iterables from the Guava library
  return Joiner.on(", ").join(Iterables.limit(Iterables.cycle("?"), num));
}

/**
 * Gets the set of IDs associated with a given list of words
 */
public Set<Integer> find(Connection conn, List<String> words)
    throws SQLException {
  Set<Integer> result = new HashSet<>();
  try(PreparedStatement ps = conn.prepareStatement(
      "SELECT id FROM my_table WHERE Word IN ("+
      getLineOfQs(words.size())+")")) {
    for(int i = 0; i < words.size(); i++) {
      ps.setString(i+1, words.get(i));
    }

    try (ResultSet rs = ps.executeQuery()) {
      while(rs.next()) {
        result.add(rs.getInt("id"));
      }
    }
  }
  return result;
}

Ce n'est pas trop pénible à coder, vous offre la sécurité d'utiliser PreparedStatement et évite les accès inutiles à la base de données.

10
dimo414

Comme indiqué dans d'autres réponses, les mises à jour par lots JDBC ne fonctionnent pas pour les requêtes SELECT ou ne sont au moins pas destinées à être utilisées pour cela.

Étant donné que la question mentionne cependant DB2 comme le SGBDR, je pense qu'il convient de souligner ici (quoique un peu tard maintenant ...), que le pilote officiel de cette base de données particulière le fait offre cette fonctionnalité en utilisant DB2PreparedStatement#executeDB2QueryBatch() (voir documentation pour plus de détails). Je ne connais aucun autre pilote JDBC avec cette fonctionnalité.

3
knutwannheden

AddBatch () est destiné aux instructions "supprimer"/"insérer"/"mettre à jour" et non aux instructions "sélectionner".

3
user963666