jdbc 系列文章列表, 请查看目录: 《jdbc学习笔记》
当需要执行批量插入或批量更新操作时, 普通的一条sql一提交方式, sql执行效率很低. 对此我们可以借助于JDBC 的批量提交机制, 可以大幅提升批量操作性能. 对于JDBC 支持两种批量操作方式:
单条sql批量传参: 借助于PreparedStatment 实现, 最常用多条sql批量操作: 借助于Statment实现, 不常用对于常见的批量操作, 有如下几种方式:
每条sql独立提交事务: 类似于使用hibernate, mybatis 等封装好的API. 因为默认使用的Connection为自动提交事务, 因此也无法回滚事务.一次性提交事务: 需要设置Connection事务提交方式为手工, 然后最后一次性提交一次性提交事务, 通过批量API: 需要设置Connection事务提交方式为手工, 然后使用批量API对于获取数据库连接, 实现方式较多, 对测试并无影响, 所以笔者封装了一个工具类为DbConnUtil.
public class TestBatch { // 批量数量 private static final int BATCH_NUM = 100000; // 执行之前清空表 @Before public void setUp() throws Exception { // 定义sql String sql = "truncate table t_user"; // 1. 获取连接 Connection connection = DbConnUtil.getConnection(); // 2. 创建PreparedStatement对象 PreparedStatement preparedStatement = connection.prepareStatement(sql); // 4. 执行sql preparedStatement.executeUpdate(); } // 批量操作: 每条sql 单独提交事务 @Test public void test_batch1() throws Exception { long start = System.currentTimeMillis(); // 定义sql String sql = "insert into t_user values (? , ?, ?)"; // 1. 获取连接 Connection connection = DbConnUtil.getConnection(true); // 2. 创建PreparedStatement对象 PreparedStatement preparedStatement = connection.prepareStatement(sql); // 3. 批量操作 for (int i = 0; i < BATCH_NUM; i++) { // 3.1 为每条sql(相同sql)设置参数 preparedStatement.setInt(1, i); preparedStatement.setString(2, "usr_" + i); preparedStatement.setString(3, "pwd_" + i); // 3.2 单独执行每条sql preparedStatement.executeUpdate(); } // 5. 释放连接 DbConnUtil.release(preparedStatement, connection); long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end - start)); } // 批量操作: 手工事务, 一次性提交 @Test public void test_batch2() throws Exception { long start = System.currentTimeMillis(); // 定义sql String sql = "insert into t_user values (? , ?, ?)"; // 1. 获取连接 Connection connection = DbConnUtil.getConnection(false); // 2. 创建PreparedStatement对象 PreparedStatement preparedStatement = connection.prepareStatement(sql); // 3. 批量操作 for (int i = 0; i < BATCH_NUM; i++) { // 3.1 为每条sql(相同sql)设置参数 preparedStatement.setInt(1, i); preparedStatement.setString(2, "usr_" + i); preparedStatement.setString(3, "pwd_" + i); // 3.2 单独执行每条sql preparedStatement.executeUpdate(); } // 4. 提交事务 connection.commit(); // 5. 释放连接 DbConnUtil.release(preparedStatement, connection); long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end - start)); // 共耗时:25053 } // 批量操作: 一次性提交事务, 批量API @Test public void testBatch3() throws Exception{ long start = System.currentTimeMillis(); // 定义sql String sql = "insert into t_user values (? , ?, ?)"; // 1. 获取数据库连接 Connection connection = DbConnUtil.getConnection(false); // 2. 创建PreparedStatement对象 PreparedStatement preStat = connection.prepareStatement(sql); // 3. 批量设置参数 for (int i = 0; i < BATCH_NUM; i++) { preStat.setInt(1, i); preStat.setString(2, "usr_" + i); preStat.setString(3, "pwd_" + i); // 将当前sql和参数作为一条命令添加到命令列表中 preStat.addBatch(); // 每1000条命令发送一条sql if ((i + 1) % 100 == 0) { preStat.executeBatch(); // int a = 1/0; 模拟异常, 测试事务回滚 } } // 4. 执行批量队列中剩余的sql preStat.executeBatch(); // 5.提交事务 connection.commit(); // 6.关闭连接 DbConnUtil.release(preStat, connection); long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end - start)); } }