Statement和PreparedStatement批量更新

本文介绍如何使用PreparedStatement进行数据库批量插入操作,包括使用addBatch()和executeBatch()方法实现上万条记录的高效插入,同时讨论了如何避免OutOfMemoryError问题并提供了分批次插入的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PreparedStatement:

1) addBatch()将一组参数添加到PreparedStatement对象内部。

2) executeBatch()将一批参数提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。

Statement:

1) addBatch(String sql)方法会在批处理缓存中加入一条sql语句。

2) executeBatch()执行批处理缓存中的所有sql语句。

注意:PreparedStatement中使用批量更新时,要先设置好参数后再使用addBatch()方法加入缓存。批量更新中只能使用更改、删除或插入语句。



package com.jdbcapi;

import java.sql.Connection;
import java.sql.Statement;

public class StatementTest {

    /**
     * 功能:请描述该方法具体功能<br/>
     * 2014-5-8 上午11:21:26
     */
    public static void main(String[] args)throws Exception {
    // TODO Auto-generated method stub
    ConnectionFactory cf1 = ConnectionFactory.getInstance();
    Connection con = cf1.getConnection();
    Statement ps = con.createStatement();
    try {
        con.setAutoCommit(false);
        ps.addBatch("insert into student values(41,'tb',null,63)");
        ps.addBatch("insert into student values(42,'tbb',null,64)");
        ps.addBatch("insert into student values(43,'tbbb',null,65)");
        ps.executeBatch();
        con.commit();
        System.out.println("提交成功");
    } catch (Exception e) {
        e.printStackTrace();
        if (!con.isClosed()) {
        
        con.rollback();
        }
    }finally{
        System.out.println("关闭连接");
        ConnectionFactory.close(con, ps,null);
    }
    
    }

}



package com.jdbcapi;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;

public class PreparedStatementTest {

    /**
     * 功能:请描述该方法具体功能<br/>
     * 2014-5-8 上午11:21:26
     */
    public static void main(String[] args)throws Exception {
    // TODO Auto-generated method stub
    ConnectionFactory cf1 = ConnectionFactory.getInstance();
    Connection con = cf1.getConnection();
    PreparedStatement ps = con.prepareStatement("insert into student values(?,?,?,?)");
    try {
        con.setAutoCommit(false);
        ps.setInt(1,18);
        ps.setString(2,"test1");
        ps.setDate(3,null);
        ps.setFloat(4,78);
        ps.addBatch();
        
        ps.setInt(1,36);
        ps.setString(2,"test2");
        ps.setDate(3,null);
        ps.setFloat(4,90);
        ps.addBatch();
        
        // 将一批参数提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组
        ps.executeBatch();
        con.commit();
        System.out.println("提交成功");
    } catch (Exception e) {
        e.printStackTrace();
        if (!con.isClosed()) {
        
        con.rollback();
        }
    }finally{
        
        ConnectionFactory.close(con, ps,null);
    }
    
    }

}



注意:JDBC的批处理不能加入select语句,否则会抛异常:
java.sql.BatchUpdateException: Can not issue SELECT via executeUpdate().
  at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:1007)

















考虑这样一个场景,在您想要插入到数据库使用批处理上万条记录。嗯,可能产生的OutOfMemoryError:

java.lang.OutOfMemoryError: Java heap space
com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)
com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)
org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)

这是因为你试图在一个批次添加所有语句,并一次插入。最好的办法是将执行分批次。看看下面的解决方案

Smart Insert: Batch within Batch - 智能插入:将整批分批
这是一个简单的解决方案。考虑批量大小为1000,每1000个查询语句为一批插入提交。

String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
final int batchSize = 1000;
int count = 0;
for (Employee employee: employees) {
    ps.setString(1, employee.getName());
    ps.setString(2, employee.getCity());
    ps.setString(3, employee.getPhone());
    ps.addBatch();
    if(++count % batchSize == 0) {
        ps.executeBatch();   // executeBatch() 返回后,将重新将语句的内部批处理命令列表设置为空。
    }
}
ps.executeBatch(); // insert remaining records
ps.close();
connection.close();

这才是理想的解决方案,它避免了SQL注入和内存不足的问题。看看我们如何递增计数器计数,一旦BATCHSIZE 达到 1000,我们调用executeBatch()提交。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值