2010-12-04 107 views
61

我想用Java一次性将多行插入到MySQL表中。行数是动态的。在过去,我在做......Java:使用PreparedStatement将多行插入MySQL

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,我不知道有什么方法要做到这一点,因为我事先不知道有多少元素array将包含。如果PreparedStatement不可能,我该怎么做(并且仍然在数组中的值)?

回答

123

您可以通过PreparedStatement#addBatch()创建批次并通过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驱动程序和/或数据块可能有一批长度的限制。

参见:

+0

完美,谢谢! – 2010-12-04 20:17:42

+21

如果你把它们放在交易中,你的插入会更快......换句话说就是用`connection.setAutoCommit(false);`和`connection.commit();`http://download.oracle.com/javase/tutorial/包装jdbc/basics/transactions.html – 2010-12-04 20:39:01

+0

感谢提示,约书亚! – 2010-12-04 20:41:23

4

如果你可以创建你的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(); 
0

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

我们可以用声明,对于禁用自动提交bacth更新的PreparedStatement,和CallableStatement对象

addBatch()则ExecuteBatch()功能适用于所有Statement对象有BATCHUPDATE

这里addBatch()方法向当前批次添加一组语句或参数。

17

当使用MySQL驱动程序,您必须设置连接PARAM rewriteBatchedStatements为true(JDBC:MySQL的://本地主机:3306/TESTDB rewriteBatchedStatements =真)。

使用此参数,当表被锁定一次并且索引只更新一次时,该语句将被重写为批量插入。所以它快得多。

没有这个参数,唯一的好处是清洁的源代码。

2

如果您在表中自动增量并需要访问它,您可以使用以下方法...使用前请先进行测试,因为它取决于使用的驱动程序中的getGeneratedKeys()。以下代码在Maria DB 10.0.12和Maria JDBC驱动程序1上进行了测试。2

请记住,增加批量大小只会在一定程度上提高性能......对于我的设置,增加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(); 
    } 
} 
2

@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(); 
相关问题