【问题标题】:JDBC insert multiple rowsJDBC插入多行
【发布时间】:2012-08-14 07:17:07
【问题描述】:

我现在正在使用批处理:

String query = "INSERT INTO table (id, name, value) VALUES (?, ?, ?)";
PreparedStatement ps = connection.prepareStatement(query);            
for (Record record : records) {
    ps.setInt(1, record.id);
    ps.setString(2, record.name);
    ps.setInt(3, record.value);
    ps.addBatch();
}
ps.executeBatch();

我只是想知道上面的代码是否等同于下面的代码。如果没有,哪个更快?

String query = "INSERT INTO table (id, name, value) VALUES ";
for (Record record : records) {
    query += "(" + record.id + ",'" + record.name + "'," + record.value + "),";
}
query = query.substring(1, query.length() - 1);
PreparedStatement ps = connection.prepareStatement(query);
ps.executeUpdate();

【问题讨论】:

    标签: java mysql jdbc batch-file


    【解决方案1】:

    关闭自动提交

    只要将autocommit 设置为false,executeBatch 的性能就会比executeUpdate 有所提高:

    connection.setAutoCommit(false);  
    PreparedStatement ps = connection.prepareStatement(query);            
    for (Record record : records) {
        // etc.
        ps.addBatch();
    }
    ps.executeBatch();
    connection.commit(); 
    

    【讨论】:

    • 我们应该在完成后将 autoCommit 设置回 true 吗?
    • 这取决于。您希望其他地方的事务自动提交吗?
    【解决方案2】:

    首先,使用查询字符串连接,您不仅会丢失 PreparedStatement 方法原生的类型转换,而且还容易受到在数据库中执行的恶意代码的攻击。

    其次,PreparedStatements 之前缓存在数据库本身中,这已经比普通 Statements 提供了非常好的性能改进。

    【讨论】:

      【解决方案3】:

      如果要插入的项目数量很大,您可能会面临严重的性能问题。因此,更安全的做法是定义一个batch size,并在达到batch size时不断执行查询。

      类似于以下示例代码的内容应该可以工作。有关如何有效使用此代码的完整故事,请参阅link

      private static void insertList2DB(List<String> list) {
              final int batchSize = 1000; //Batch size is important.
              Connection conn = getConnection();
              PreparedStatement ps = null;
              try {
                  String sql = "INSERT INTO theTable (aColumn) VALUES (?)";
                  ps = conn.prepareStatement(sql);
      
                  int insertCount=0;
                  for (String item : list) {
                      ps.setString(1, item);
                      ps.addBatch();
                      if (++insertCount % batchSize == 0) {
                          ps.executeBatch();
                      }
                  }
                  ps.executeBatch();
      
              } catch (SQLException e) {
                  e.printStackTrace();
                  System.exit(1);
              }
          finally {
              try {
                  ps.close();
                  conn.close();
              } catch (SQLException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          }
      } 
      

      【讨论】:

        【解决方案4】:

        如果您的记录大小小于或等于 1000,则以下代码优于您的两个代码:

        StringBuilder query = new StringBuilder("INSERT INTO table (id, name, value) VALUES ");
        
        if (records.size() <= 1000) {
            
            for (int i = 0; i < records.size(); i++)
                query.append("(?, ?, ?), ");
        
            query = new StringBuilder(query.substring(1, query.length() - 1));
        
            PreparedStatement ps = connection.prepareStatement(query.toString());
        
            for (int i = 0; i < records.size(); i++) {
                ps.setInt((i * 3) + 1, record.id);
                ps.setString((i * 3) + 2, record.name);
                ps.setInt((i * 3) + 3, record.value);
            }
            
            ps.executeUpdate();
            
        }
        

        通过这种方式,您可以使用 PreparedStatement 并根据记录列表的大小在一个插入查询中使用多个值子句动态创建它

        【讨论】:

          【解决方案5】:
          public void insertBatch(final List<Record > records ) {
          
              String query = "INSERT INTO table (id, name, value) VALUES (?, ?, ?)";
          
          
              GenericDAO.getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {
          
          
                  @Override
                  public void setValues(PreparedStatement ps, int i) throws SQLException {
                        Record record = records .get(i);
                        ps.setInt(1, record.id);
                        ps.setString(2, record.name);
                        ps.setInt(3, record.value);
                  }
          
                  @Override
                  public int getBatchSize() {
                      return records.size();
                  }
              });
          }
          

          【讨论】:

          • 这个例子最好多解释几句。
          • 使用spring jdbctemplete
          【解决方案6】:

          我觉得这样就可以了

          String query = "INSERT INTO table (id, name, value) VALUES ";
          for (Record record : records)
          {
          query += "(" + record.id + ",'" + record.name + "'," + record.value + "),";
          query = query.substring(1, query.length() - 1);
          PreparedStatement ps = connection.prepareStatement(query);
          ps.executeUpdate();
          }
          

          因为您必须对要插入数据库的每条记录执行查询。

          【讨论】:

            猜你喜欢
            • 2010-09-17
            • 1970-01-01
            • 2015-09-28
            • 2011-07-07
            • 1970-01-01
            • 2017-06-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多