JDBC Batch


使用JDBC操作数据库的时候,经常会执行一些批量操作。

例如,一次性给会员增加可用优惠券若干,我们可以执行以下SQL代码:

  1. INSERT INTO coupons (user_id, type, expires) VALUES (123, 'DISCOUNT', '2030-12-31');
  2. INSERT INTO coupons (user_id, type, expires) VALUES (234, 'DISCOUNT', '2030-12-31');
  3. INSERT INTO coupons (user_id, type, expires) VALUES (345, 'DISCOUNT', '2030-12-31');
  4. INSERT INTO coupons (user_id, type, expires) VALUES (456, 'DISCOUNT', '2030-12-31');
  5. ...

实际上执行JDBC时,因为只有占位符参数不同,所以SQL实际上是一样的:

  1. for (var params : paramsList) {
  2. PreparedStatement ps = conn.preparedStatement("INSERT INTO coupons (user_id, type, expires) VALUES (?,?,?)");
  3. ps.setLong(params.get(0));
  4. ps.setString(params.get(1));
  5. ps.setString(params.get(2));
  6. ps.executeUpdate();
  7. }

类似的还有,给每个员工薪水增加10%~30%:

  1. UPDATE employees SET salary = salary * ? WHERE id = ?

通过一个循环来执行每个PreparedStatement虽然可行,但是性能很低。SQL数据库对SQL语句相同,但只有参数不同的若干语句可以作为batch执行,即批量执行,这种操作有特别优化,速度远远快于循环执行每个SQL。

在JDBC代码中,我们可以利用SQL数据库的这一特性,把同一个SQL但参数不同的若干次操作合并为一个batch执行。我们以批量插入为例,示例代码如下:

  1. try (PreparedStatement ps = conn.prepareStatement("INSERT INTO students (name, gender, grade, score) VALUES (?, ?, ?, ?)")) {
  2. // 对同一个PreparedStatement反复设置参数并调用addBatch():
  3. for (Student s : students) {
  4. ps.setString(1, s.name);
  5. ps.setBoolean(2, s.gender);
  6. ps.setInt(3, s.grade);
  7. ps.setInt(4, s.score);
  8. ps.addBatch(); // 添加到batch
  9. }
  10. // 执行batch:
  11. int[] ns = ps.executeBatch();
  12. for (int n : ns) {
  13. System.out.println(n + " inserted."); // batch中每个SQL执行的结果数量
  14. }
  15. }

执行batch和执行一个SQL不同点在于,需要对同一个PreparedStatement反复设置参数并调用addBatch(),这样就相当于给一个SQL加上了多组参数,相当于变成了“多行”SQL。

第二个不同点是调用的不是executeUpdate(),而是executeBatch(),因为我们设置了多组参数,相应地,返回结果也是多个int值,因此返回类型是int[],循环int[]数组即可获取每组参数执行后影响的结果数量。

练习

JDBC Batch - 图1下载练习:使用Batch操作 (推荐使用IDE练习插件快速下载)

小结

使用JDBC的batch操作会大大提高执行效率,对内容相同,参数不同的SQL,要优先考虑batch操作。

读后有收获可以支付宝请作者喝咖啡:

JDBC Batch - 图2