文档章节

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

囚兔
 囚兔
发布于 2016/06/30 13:39
字数 968
阅读 133
收藏 2
点赞 0
评论 0

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,其他成功执行的命令依然会提交到数据库,否则不关执行成功与否都不会提交到数据库。

© 著作权归作者所有

共有 人打赏支持
囚兔

囚兔

粉丝 38
博文 75
码字总数 45682
作品 1
南京
程序员
大型互联网架构必备技术——性能调优专题

性能调优 深入内核,直击故障 ,拒绝蒙圈 性能优化如何理解 1、性能基准 2、什么是性能优化 3、衡量标准 JVM调优 1、Jvm虚拟机内存剖析 2、垃圾收集器 3、实战调优案例与解决方案 4、Jvm运行...

Java高级架构 ⋅ 04/15 ⋅ 0

sharding-jdbc事务解读

序言 sharding-jdbc在分库分表方面提供了很大的便利性,在使用DB的时候,通常都会涉及到事务这个概念,而在分库分表的环境上再加上事务,就会使事情变得复杂起来。本章试图剖析sharding-jdbc...

xiaomin0322 ⋅ 06/06 ⋅ 0

Java反斜线(\)路径与转义字符的小坑

1.图片路径字段ImagePath, 从数据库读出,写到前台变量中, 正常(比如: uploadimage201818802-8517A000800002-1.jpg) 2.由前台向后台提交, getParameter取出则反斜线成了转义符(字符串变为: u...

javado ⋅ 06/11 ⋅ 0

集成 Proxy 与 DB Mesh,Sharding-JDBC 3 将"Sharding"做到极致

嘉宾:张亮 作者:雨多田光 提起数据库中间件,我们可以很自然地联想到 OneProxy、TDSQL、Sharding-JDBC 与 MyCat 等知名项目。在众多的数据库中间件实现技术中,通常存在两种架构模式,一种...

编辑部的故事 ⋅ 05/23 ⋅ 18

基于可靠消息方案的分布式事务(二):Java中的事务

前言:在上一篇文章 基于可靠消息方案的分布式事务:Lottor介绍 中介绍了常见的分布式事务的解决方案以及笔者基于可靠消息方案实现的分布式事务组件Lottor的原理,并展示了应用的控制台管理。...

aoho ⋅ 06/01 ⋅ 0

MyCAT PreparedStatement 重新入门

概述 相信很多同学在学习 JDBC 时,都碰到 和 。究竟该使用哪个呢?最终很可能是懵里懵懂的看了各种总结,使用 。那么本文,通过 MyCAT 对 的实现对大家能够重新理解下。 本文主要分成两部分...

wangchen1999 ⋅ 05/02 ⋅ 0

OpenCV 离散傅里叶变换 JAVA 实现的问题

小弟最近在学习 OpenCV3 ,使用 Java 实现,看的书是《OpenCV3 编程入门》。说实话这本书针对 JAVA 语言参考价值一般,基本是顺着他的思路把JAVA 官方说明文档(http://opencv-java-tutorial...

35Niu ⋅ 04/17 ⋅ 0

sharding-jdbc源码解析全集

sharding-jdbc源码解析之词法解析 sharding源码解析之api分析 sharding-jdbc源码解析之spring集成 sharding-jdbc源码解析之spring集成分片构造实现 sharding-jdbc源码解析之jdbc规范重写 sh...

天河2018 ⋅ 05/03 ⋅ 0

DB大量出现select @@session.tx_read_only

在一次捞取Top SQL中,发现DB大量执行select @@session.txreadonly,几乎每一条DML语句前,都会有这么一个sql。但是应用层并没有做特殊处理,那么这个SQL语句有什么作用?是谁执行了它? 此s...

Hosee ⋅ 04/18 ⋅ 0

「游戏引擎Mojoc」(10)Android NDK通用JNI调用Java代码封装

Mojoc提供了一个通用的工具类,来调用Android Java代码,以实现特定平台的功能。这个工具类封装了JNI使用的繁琐细和上下文对象的获取,提供了简单直接的API专注于Java类和方法的访问,并且实...

scottcgi ⋅ 05/20 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

骰子游戏代码开源地址

因为阿里云现在服务器已经停用了,所以上面的配置已经失效。 服务端开源地址:https://gitee.com/goalya/chat4.git 客户端开源地址:https://gitee.com/goalya/client4.git 具体运行界面请参考...

算法之名 ⋅ 36分钟前 ⋅ 0

设计模式--装饰者模式

装饰者模式 定义 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。 通用类图 意图 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比...

gaob2001 ⋅ 今天 ⋅ 0

JavaScript零基础入门——(八)JavaScript的数组

JavaScript零基础入门——(八)JavaScript的数组 欢迎大家回到我们的JavaScript零基础入门,上一节课我们讲了有关JavaScript正则表达式的相关知识点,便于大家更好的对字符串进行处理。这一...

JandenMa ⋅ 今天 ⋅ 0

sbt网络问题解决方案

转自:http://dblab.xmu.edu.cn/blog/maven-network-problem/ cd ~/.sbt/launchers/0.13.9unzip -q ./sbt-launch.jar 修改 vi sbt/sbt.boot.properties 增加一个oschina库地址: [reposit......

狐狸老侠 ⋅ 今天 ⋅ 0

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 今天 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 今天 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

Spring 依赖注入(DI)

1、Setter方法注入: 通过设置方法注入依赖。这种方法既简单又常用。 类中定义set()方法: public class HelloWorldOutput{ HelloWorld helloWorld; public void setHelloWorld...

霍淇滨 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部