Java:使用PreparedStatement将多行插入到MySQL中

我想用Java一次插入多行到一个MySQL表中。 行数是dynamic的。 过去我在做…

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

我想优化这个使用MySQL支持的语法:

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

但用PreparedStatement我不知道有什么办法做到这一点,因为我事先不知道有多less元素array将包含。 如果PreparedStatement是不可能的,那我还能怎么做(并且仍然在数组中的值)?

您可以通过PreparedStatement#addBatch()创build一个批处理,并通过PreparedStatement#executeBatch()执行它。

这是一个开球的例子:

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

每1000个项目执行一次,因为一些JDBC驱动程序和/或DB可能会限制批处理长度。

另见

  • JDBC教程 – 使用PreparedStatement
  • JDBC教程 – 使用Statement对象进行批量更新

当使用MySQL驱动程序时,必须将连接参数rewriteBatchedStatements设置为true(jdbc:mysql:// localhost:3306 / TestDB? rewriteBatchedStatements = true )。

使用这个参数,当表被locking一次,索引只更新一次时,语句将被重写为批量插入。 所以它快得多。

如果没有这个参数,只能使用更简洁的源代码。

如果您可以dynamic创build您的SQL语句,您可以执行以下解决方法:

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

如果你在表中有自动增量,并且需要访问它,你可以使用下面的方法…在使用之前做testing,因为语句中的getGeneratedKeys(),因为它取决于所使用的驱动程序。 以下代码在Maria DB 10.0.12和Maria JDBC驱动程序1.2上进行了testing

请记住,增加批量大小只会在一定程度上提高性能……对于我的设置,将批量增加到500以上实际上会降低性能。

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

@Ali Shakiba你的代码需要一些修改。 错误部分:

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

更新的代码:

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

我们可以在JDBC中一起提交多个更新来提交批量更新。

我们可以使用Statement,PreparedStatement和CallableStatement对象进行bacth更新,并禁用自动提交

addBatch()executeBatch()函数与所有语句对象一起提供BatchUpdate

这里addBatch()方法将一组语句或参数添加到当前批处理中。

Interesting Posts