Java: insérer plusieurs lignes dans MySQL avec PreparedStatement

Je veux insérer plusieurs lignes dans une table MySQL à la fois en utilisant Java. Le nombre de lignes est dynamic. Dans le passé je faisais …

for (Ssortingng element : array) { myStatement.setSsortingng(1, element[0]); myStatement.setSsortingng(2, element[1]); myStatement.executeUpdate(); } 

Je voudrais optimiser ceci pour utiliser la syntaxe supscope par MySQL:

 INSERT INTO table (col1, col2) VALUES ('val1', 'val2'), ('val1', 'val2')[, ...] 

mais avec un PreparedStatement je ne connais aucun moyen de le faire car je ne sais pas combien d’éléments le array contiendra. Si ce n’est pas possible avec un PreparedStatement , comment puis-je le faire (et toujours échapper aux valeurs du tableau)?

Vous pouvez créer un lot par PreparedStatement#addBatch() et l’exécuter par PreparedStatement#executeBatch() .

Voici un exemple de coup d’envoi:

 public void save(List entities) throws SQLException { try ( Connection connection = database.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL_INSERT); ) { int i = 0; for (Entity entity : entities) { statement.setSsortingng(1, entity.getSomeProperty()); // ... statement.addBatch(); i++; if (i % 1000 == 0 || i == entities.size()) { statement.executeBatch(); // Execute every 1000 items. } } } } 

Il est exécuté tous les 1 000 éléments, car certains pilotes JDBC et / ou certaines bases de données peuvent être limités en longueur de lot.

Voir aussi :

  • Tutoriel JDBC – Utilisation de PreparedStatement
  • Tutoriel JDBC – Utilisation d’objects Statement pour les mises à jour par lots

Lorsque le pilote MySQL est utilisé, vous devez définir le paramètre de connexion rewriteBatchedStatements sur true (jdbc: mysql: // localhost: 3306 / TestDB? RewriteBatchedStatements = true ).

Avec ce paramètre, l’instruction est réécrite en bloc lorsque la table est verrouillée une seule fois et que les index ne sont mis à jour qu’une seule fois. Donc c’est beaucoup plus rapide.

Sans ce paramètre, seul le code source est plus propre.

Si vous pouvez créer votre instruction sql de manière dynamic, vous pouvez procéder comme suit:

  Ssortingng myArray[][] = { { "1-1", "1-2" }, { "2-1", "2-2" }, { "3-1", "3-2" } }; SsortingngBuffer mySql = new SsortingngBuffer( "insert into MyTable (col1, col2) values (?, ?)"); for (int i = 0; i < myArray.length - 1; i++) { mySql.append(", (?, ?)"); } myStatement = myConnection.prepareStatement(mySql.toString()); for (int i = 0; i < myArray.length; i++) { myStatement.setString(i, myArray[i][1]); myStatement.setString(i, myArray[i][2]); } myStatement.executeUpdate(); 

Dans le cas où vous avez un incrément automatique dans la table et que vous avez besoin d’y accéder, vous pouvez utiliser l’approche suivante … Faites un test avant d’utiliser parce que getGeneratedKeys () dans Statement car cela dépend du pilote utilisé. Le code ci-dessous est testé sur les pilotes Maria DB 10.0.12 et Maria JDBC 1.2.

Rappelez-vous que l’augmentation de la taille des lots n’améliore les performances que dans une certaine mesure.

 public Connection getConnection(boolean autoCommit) throws SQLException { Connection conn = dataSource.getConnection(); conn.setAutoCommit(autoCommit); return conn; } private void testBatchInsert(int count, int maxBatchSize) { Ssortingng querySql = "insert into batch_test(keyword) values(?)"; try { Connection connection = getConnection(false); PreparedStatement pstmt = null; ResultSet rs = null; boolean success = true; int[] executeResult = null; try { pstmt = connection.prepareStatement(querySql, Statement.RETURN_GENERATED_KEYS); for (int i = 0; i < count; i++) { pstmt.setString(1, UUID.randomUUID().toString()); pstmt.addBatch(); if ((i + 1) % maxBatchSize == 0 || (i + 1) == count) { executeResult = pstmt.executeBatch(); } } ResultSet ids = pstmt.getGeneratedKeys(); for (int i = 0; i < executeResult.length; i++) { ids.next(); if (executeResult[i] == 1) { System.out.println("Execute Result: " + i + ", Update Count: " + executeResult[i] + ", id: " + ids.getLong(1)); } } } catch (Exception e) { e.printStackTrace(); success = false; } finally { if (rs != null) { rs.close(); } if (pstmt != null) { pstmt.close(); } if (connection != null) { if (success) { connection.commit(); } else { connection.rollback(); } connection.close(); } } } catch (SQLException e) { e.printStackTrace(); } } 

@Ali Shakiba Votre code a besoin d’être modifié. Partie d’erreur:

 for (int i = 0; i < myArray.length; i++) { myStatement.setString(i, myArray[i][1]); myStatement.setString(i, myArray[i][2]); } 

Code mis à jour:

 Ssortingng myArray[][] = { {"1-1", "1-2"}, {"2-1", "2-2"}, {"3-1", "3-2"} }; SsortingngBuffer mySql = new SsortingngBuffer("insert into MyTable (col1, col2) values (?, ?)"); for (int i = 0; i < myArray.length - 1; i++) { mySql.append(", (?, ?)"); } mysql.append(";"); //also add the terminator at the end of sql statement myStatement = myConnection.prepareStatement(mySql.toString()); for (int i = 0; i < myArray.length; i++) { myStatement.setString((2 * i) + 1, myArray[i][1]); myStatement.setString((2 * i) + 2, myArray[i][2]); } myStatement.executeUpdate(); 

Nous pouvons soumettre plusieurs mises à jour ensemble dans JDBC pour soumettre des mises à jour par lots.

nous pouvons utiliser des objects Statement, PreparedStatement et CallableStatement pour la mise à jour de bacth avec la désactivation de la validation automatique

Les fonctions addBatch () et executeBatch () sont disponibles avec tous les objects d’instruction pour avoir BatchUpdate

La méthode addBatch () ajoute un ensemble d’instructions ou de parameters au lot en cours.