专栏首页IT杂记JDBC批量提交SQL的几点问题解答

JDBC批量提交SQL的几点问题解答

1. 疑问

  • 问题一:Statement的executeBatch方法是否会执行commit操作,是否还需要再执行一次commit()?
  • 问题二:执行批量操作的过程中,如果其中有部分命令执行失败,其他执行成功的命令是否会提交到数据库?

2. 环境

    测试采用MySQL数据库,创建如下表;

CREATE TABLE `batch_test` (
`id`  int(11) NOT NULL ,
PRIMARY KEY (`id`)
)

3. 测试

3.1. 问题一测试

    测试代码:

Connection conn = null;
Statement stmt = null;

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (2)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (3)");

    stmt.executeBatch();
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    结果:

mysql> select * from batch_test;
Empty set

    修改代码,增加commit()

Connection conn = null;
Statement stmt = null;

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (2)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (3)");

    stmt.executeBatch();

    // ************
    conn.commit();

} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    结果:

mysql> select * from batch_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set

对比上面两个测试,说明在执行executeBatch()后必须再执行commit(), executeBatch不会执行commit操作;

3.2. 问题二测试

    接着3.1的测试数据,目前表batch_test中已经有三条记录,id字段是主键,并且已经存在三个值(1,2,3),我再依次添加4条insert命令,id值顺序为(4,5,1,6),当执行executeBatch时第三条记录(id=1)应该会失败,且抛出异常。

    代码如下:

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (4)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (5)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (6)");

    stmt.executeBatch();
    System.out.println("executeBatch");

    conn.commit();
    System.out.println("commit");

} catch (BatchUpdateException e) {
    e.printStackTrace();
    System.out.println("UpdateCounts -> " + Arrays.toString(e.getUpdateCounts()));
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    执行executeBatch()时抛异常BatchUpdateException,输出:

java.sql.BatchUpdateException: Duplicate entry '1' for key 'PRIMARY'     at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:1110)     at com.tiza.test.db.BatchExecTest.main(BatchExecTest.java:26)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at java.lang.reflect.Method.invoke(Method.java:606)     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) UpdateCounts -> [1, 1, -3, 1]

结果:

mysql> select * from batch_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
+----+
3 rows in set

    根据结果可知,批量操作当出现一条SQL命令失败,会抛异常,并且UpdateCounts显示,除了id=1的记录执行失败,其他三条都成功了。 但是这里抛异常后就没有执行commit,那如果执行commit是不是三条成功的(id=4,id=5,id=6)就会提交到数据库?

    进一步测试,在抛BatchUpdateException后依然做commit,代码如下:

Connection conn = null;
Statement stmt = null;

try {
    conn = DBUtils.getConnection();
    conn.setAutoCommit(false);

    stmt = conn.createStatement();
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (4)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (5)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (1)");
    stmt.addBatch("INSERT INTO batch_test(id) VALUES (6)");

    stmt.executeBatch();
    System.out.println("executeBatch");

    conn.commit();
    System.out.println("commit");

} catch (BatchUpdateException e) {
    e.printStackTrace();
    System.out.println("UpdateCounts -> " + Arrays.toString(e.getUpdateCounts()));

    // **********************
    try {
        conn.commit();
    } catch (SQLException e1) {
        e1.printStackTrace();
    }
    // **********************

} catch (SQLException e) {
    e.printStackTrace();
} finally {
    DBUtils.close(conn, stmt);
}

    输出:

java.sql.BatchUpdateException: Duplicate entry '1' for key 'PRIMARY'     at com.mysql.jdbc.StatementImpl.executeBatch(StatementImpl.java:1110)     at com.tiza.test.db.BatchExecTest.main(BatchExecTest.java:26)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     at java.lang.reflect.Method.invoke(Method.java:606)     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) UpdateCounts -> [1, 1, -3, 1]

    结果:

mysql> select * from batch_test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
|  6 |
+----+
6 rows in set

至此问题二答案已经出来了,批量提交过程中虽然在执行executeBatch时当部分命令出现异常,但是只要继续执行commit,其中成功执行的命令还是会commit到数据库的。

4. 总结

问题一:Statement的executeBatch方法是否会执行commit操作,是否还需要再执行一次commit()?

答: executeBatch不会执行commit,在执行完executeBatch后必须再执行commit;

问题二:执行批量操作的过程中,如果其中有部分命令执行失败,其他执行成功的命令是否会提交到数据库?

答: 批量操作执行executeBatch时部分命令执行失败会抛BatchUpdateException异常,但是只要继续执行commit,其他成功执行的命令依然会提交到数据库,否则不关执行成功与否都不会提交到数据库。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 求一个数组中子数组的最大和算法(Java实现)

        前几天在微信订阅号“待字闺中”中看到的一篇文章《小技巧求一个数组中子数组的最大和》,提供下Java的实现,并且在对题目做下小修改,本来打算直接在微信里直...

    囚兔
  • JVM垃圾收集

    目录 内存区域回顾 机制介绍 收集器介绍 调优 内存区域回顾 ? 垃圾回收机制 Java 对象生命周期 ? 根搜索算法 ? ? 从GC Roots对象为起点,...

    囚兔
  • Storm客户端提交任务失败原因分析

    囚兔
  • leaflet在线地图进阶宝典——高级交互特性

    本文针对leaflet的高级交互特性进行展开,主要涉及到leaflet中等值线地图的鼠标悬浮效果及点击效果的动态呈现。这也是leaflet的天然HTML属性所具...

    数据小磨坊
  • 前沿快报 | 机器智能MI【算法模型】 | 2nd

    本周早些时候,Google发布了Android 9 Pie,这是Android的最新版本,它使用机器学习让你的手机更容易使用。Android 9...

    用户7623498
  • Java微信公众平台开发_04_自定义菜单

    自定义菜单中请求包的数据是Json字符串格式的,请参见:  Java_数据交换_fastJSON_01_用法入门

    shirayner
  • iOS XibKits-- Label内边距设置

    ZY_FlyWay
  • 从零开始打造一款简单的 apache module 后门

    记得很久以前看文章的时候里面有关于 apache module 后门的运用,时间太久都忘记那篇文章具体在哪里,关于 apache module 后门的印象也已经...

    信安之路
  • Python 学习入门(19)—— 异常

    在项目开发中,异常处理是不可或缺的。异常处理帮助人们debug,通过更加丰富的信息,让人们更容易找到bug的所在。异常处理还可以提高程序的容错性。

    阳光岛主
  • 110行JavaScript代码实现的雪花纷飞动画效果

    Jerry Wang

扫码关注云+社区

领取腾讯云代金券