Quiero insertar varias filas en una tabla MySQL a la vez usando Java. El número de filas es dinámico. En el pasado estaba haciendo ...
for (String element : array) {
myStatement.setString(1, element[0]);
myStatement.setString(2, element[1]);
myStatement.executeUpdate();
}
Me gustaría optimizar esto para usar la sintaxis compatible con MySQL:
INSERT INTO table (col1, col2) VALUES ('val1', 'val2'), ('val1', 'val2')[, ...]
pero con un PreparedStatement
no conozco ninguna forma de hacer esto ya que no sé de antemano cuántos elementos array
contendrán. Si no es posible con a PreparedStatement
, ¿de qué otra manera puedo hacerlo (y aún así escapar de los valores en la matriz)?
java
mysql
jdbc
prepared-statement
batch-insert
Tom Marthenal
fuente
fuente
connection.setAutoCommit(false);
yconnection.commit();
descargue.oracle.com/javase/tutorial/jdbc/basics/…i == entities.size()
Cuando se usa el controlador MySQL, debe establecer el parámetro de conexión
rewriteBatchedStatements
en verdadero( jdbc:mysql://localhost:3306/TestDB?**rewriteBatchedStatements=true**)
.Con este parámetro, la declaración se reescribe para inserción masiva cuando la tabla está bloqueada solo una vez y los índices se actualizan solo una vez. Entonces es mucho más rápido.
Sin este parámetro, la única ventaja es un código fuente más limpio.
fuente
5.1.45
versión del conector mysql.rewriteBatchedStatements=true
no hay ganancia de rendimiento.Si puede crear su declaración SQL dinámicamente, puede hacer la siguiente solución:
String myArray[][] = { { "1-1", "1-2" }, { "2-1", "2-2" }, { "3-1", "3-2" } }; StringBuffer mySql = new StringBuffer("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();
fuente
En caso de que tenga un incremento automático en la tabla y necesite acceder a él ... puede usar el siguiente enfoque ... Haga la prueba antes de usar porque getGeneratedKeys () en Statement porque depende del controlador utilizado. El siguiente código se prueba en Maria DB 10.0.12 y Maria JDBC driver 1.2
Recuerde que aumentar el tamaño del lote mejora el rendimiento solo hasta cierto punto ... para mi configuración, aumentar el tamaño del lote por encima de 500 en realidad degradaba el rendimiento.
public Connection getConnection(boolean autoCommit) throws SQLException { Connection conn = dataSource.getConnection(); conn.setAutoCommit(autoCommit); return conn; } private void testBatchInsert(int count, int maxBatchSize) { String 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(); } }
fuente
@Ali Shakiba, su código necesita alguna modificación. Parte de error:
for (int i = 0; i < myArray.length; i++) { myStatement.setString(i, myArray[i][1]); myStatement.setString(i, myArray[i][2]); }
Código actualizado:
String myArray[][] = { {"1-1", "1-2"}, {"2-1", "2-2"}, {"3-1", "3-2"} }; StringBuffer mySql = new StringBuffer("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();
fuente
myArray
tiene una longitud mayor que ese límite, obtendrá una excepción. En mi caso, tengo un límite de 1,000 filas que provoca la necesidad de una ejecución por lotes, porque podría estar actualizando potencialmente más de 1,000 filas en cualquier ejecución dada. En teoría, este tipo de declaración debería funcionar bien si sabe que está insertando menos del máximo permitido. Algo para tener en cuenta.podemos enviar varias actualizaciones juntas en JDBC para enviar actualizaciones por lotes.
podemos usar los objetos Statement, PreparedStatement y CallableStatement para la actualización básica con deshabilitar el compromiso automático
Las funciones addBatch () y executeBatch () están disponibles con todos los objetos de declaración para tener BatchUpdate
aquí el método addBatch () agrega un conjunto de declaraciones o parámetros al lote actual.
fuente