探讨Spring事务控制中,异常触发事务回滚原理。文章进行了6种情况下的Spring事务是否回滚。 
以下代码都是基于Spring与Mybatis整合,使用Spring声明式事务配置事务方法。

1.不捕获异常(一般处理方式)

代码,其中contentMappger.updateWithErrTest(31L); 是SQL语句错误,用来测试回滚。

    /**
* 删除多条记录
*/
@Override
public ShopResult deleteContentGroup(String[] ids) {
if (null == ids || ids.length == 0)
{
return ShopResult.error();
}
for (String idStr : ids)
{
Long id = new Long(idStr);
contentMappger.deleteByPrimaryKey(id);
}
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
return ShopResult.ok();
}

运行结果:报错,事务发生了回滚,即由于错误代码,前面的for循环删除记录事务被回滚了。

### SQL: delete form tb_content    where kid = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
; bad SQL grammar []; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
at com.mysql.jdbc.Util.getInstance(Util.java:381)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1030)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3536)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3468)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1957)
..................
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
at com.sun.proxy.$Proxy35.updateWithErrTest(Unknown Source)
at com.shop.manager.service.impl.ContentServiceImpl.deleteContentGroup(ContentServiceImpl.java:94)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
.......

2. 捕获异常,但不处理,不抛出

代码

    /**
* 删除多条记录
*/
@Override
public ShopResult deleteContentGroup(String[] ids) {
if (null == ids || ids.length == 0)
{
return ShopResult.error();
}
for (String idStr : ids)
{
Long id = new Long(idStr);
contentMappger.deleteByPrimaryKey(id);
}
try {
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
} catch (Exception e) {
//捕获异常,但不处理
System.out.println("-----nothing to do-------");
}
return ShopResult.ok();
}

运行结果:事务提交,未回滚。 

### The error occurred while setting parameters
### SQL: delete form tb_content where kid = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
]
-----nothing to do-------
2017-06-18 14:27:59,493 [http-bio-8080-exec-4] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization committing SqlSession //(事务提交)
[org.apache.ibatis.session.defaults.DefaultSqlSession@616a85a9]

3. 捕获异常,并抛出RuntimeException异常

Spring碰到Unchecked Exceptions都会回滚,不仅是RuntimeException,也包括Error。 
代码

    /**
* 删除多条记录
*/
@Override
public ShopResult deleteContentGroup(String[] ids) {
if (null == ids || ids.length == 0)
{
return ShopResult.error();
}
for (String idStr : ids)
{
Long id = new Long(idStr);
contentMappger.deleteByPrimaryKey(id);
}
try {
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
} catch (Exception e) {
System.out.println("----throw Exception-----");
throw new RuntimeException();
}
return ShopResult.ok();
}

运行结果:如预期的一样,抛出RuntimeException,事务发生回滚。

### SQL: delete form tb_content    where kid = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
]
----throw Exception-----
2017-06-18 14:21:27,928 [http-bio-8080-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3ef56e3a]
...............
2017-06-18 14:21:27,941 [http-bio-8080-exec-1] [org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver]-[DEBUG] Resolving exception from handler [public com.shop.common.pojo.ShopResult com.shop.manager.controller.ContentController.deleteContentGroup(java.lang.String)]: java.lang.RuntimeException
2017-06-18 14:21:27,941 [http-bio-8080-exec-1] [org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver]-[DEBUG] Resolving exception from handler [public com.shop.common.pojo.ShopResult com.shop.manager.controller.ContentController.deleteContentGroup(java.lang.String)]: java.lang.RuntimeException
2017-06-18 14:21:27,942 [http-bio-8080-exec-1] [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver]-[DEBUG] Resolving exception from handler [public com.shop.common.pojo.ShopResult com.shop.manager.controller.ContentController.deleteContentGroup(java.lang.String)]: java.lang.RuntimeException
2017-06-18 14:21:27,942 [http-bio-8080-exec-1] [org.springframework.web.servlet.DispatcherServlet]-[DEBUG] Could not complete request
java.lang.RuntimeException
at com.shop.manager.service.impl.ContentServiceImpl.deleteContentGroup(ContentServiceImpl.java:98) //异常
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

4.捕获异常,并继续抛出原捕获的异常

代码:

    /**
* 删除多条记录
*/
@Override
public ShopResult deleteContentGroup(String[] ids) {
if (null == ids || ids.length == 0)
{
return ShopResult.error();
}
for (String idStr : ids)
{
Long id = new Long(idStr);
contentMappger.deleteByPrimaryKey(id);
}
try {
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
} catch (Exception e) {
//捕获异常,继续抛出
System.out.println("-----throw Exception-------");
throw e;
}
return ShopResult.ok();
}

运行结果:抛出异常,事务发生回滚

### The error occurred while setting parameters
### SQL: delete form tb_content where kid = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
]
-----throw Exception-------
2017-06-18 14:36:25,308 [http-bio-8080-exec-9] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@45fe0f70]
2017-06-18 14:36:25,308 [http-bio-8080-exec-9] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization closing SqlSession //事务回滚
[org.apache.ibatis.session.defaults.DefaultSqlSession@45fe0f70]

5. 捕获异常,并抛出新new的异常(或自定义Exception异常) new Exception

代码:

    /**
* 删除多条记录
* @throws Exception
*/
@Override
public ShopResult deleteContentGroup(String[] ids) throws Exception {
if (null == ids || ids.length == 0)
{
return ShopResult.error();
}
for (String idStr : ids)
{
Long id = new Long(idStr);
contentMappger.deleteByPrimaryKey(id);
}
try {
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
} catch (Exception e) {
//捕获异常,抛出新异常
System.out.println("-----throw new Exception(e)-------");
throw new Exception(e);
}
return ShopResult.ok();
}

运行结果:事务提交,未回滚。(Spring的默认回滚异常类型不包括Exception)

### The error occurred while setting parameters
### SQL: delete form tb_content where kid = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
]
-----throw new Exception(e) -------
2017-06-18 14:43:16,098 [http-bio-8080-exec-10] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization committing SqlSession //事务提交
[org.apache.ibatis.session.defaults.DefaultSqlSession@32c4821]
2017-06-18 14:43:16,098 [http-bio-8080-exec-10] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@32c4821]

6. 在事务配置中没有设置rollback-for异常类型为Exception

<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 事务行为控制 -->
<tx:attributes>
<tx:method name="save" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.shop.manager.service.*.*(..))" />
</aop:config>
    /**
* 删除多条记录
* @throws Exception
*/
@Override
public ShopResult deleteContentGroup(String[] ids) throws Exception {
if (null == ids || ids.length == 0)
{
return ShopResult.error();
}
for (String idStr : ids)
{
Long id = new Long(idStr);
contentMappger.deleteByPrimaryKey(id);
}
try {
contentMappger.updateWithErrTest(31L); //错误代码,SQL语句错误。用来测试事务,看是否回滚
} catch (Exception e) {
//捕获异常,继续抛出
System.out.println("-----throw new Exception-------");
throw new Exception("---自定义Exception,事务中已配置rollback-for---");
}
return ShopResult.ok();
}

运行结果:如预期一样发生回滚

### The error may involve com.shop.manager.mapper.TbContentMapper.updateWithErrTest-Inline
### The error occurred while setting parameters
### SQL: delete form tb_content where kid = ?
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tb_content
where kid = 31' at line 1
]
-----throw new Exception-------
2017-06-18 15:07:02,273 [http-bio-8080-exec-8] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f177061]
2017-06-18 15:07:02,273 [http-bio-8080-exec-8] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f177061]

总结:

  1. Spring事务管理是根据异常来进行回滚操作;
  2. Spring与Mybatis整合时,虽然在Service方法中并没有check异常,但是如果数据库有异常发生,默认会进行事务回滚。
  3. Spring 如果不添加rollbackFor等属性,Spring碰到Unchecked Exceptions都会回滚,不仅是RuntimeException,也包括Error。
  4. 如果在事务方法中捕获异常并进行处理,一定要继续抛出异常并在Spring事务管理中进行rollbak-for配置。

转自:https://blog.csdn.net/ljyhust/article/details/73431968?locationNum=5&fps=1

Spring事务管理——回滚(rollback-for)控制的更多相关文章

  1. Spring事务管理回滚问题

    Spring事务管理不能回滚问题 在前段时间学习SpringMVC的练习中,碰到声明式事务管理时,事务不能回滚的情况,通过查看博客和资料,解决了问题. 原因 导致Spring事务管理不能回滚的原因有两 ...

  2. Spring事务不回滚原因分析

    Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离. 在我完成一个项目的时候,遇到了一个Spring事务不回滚的问题,通过aspectJ和@Transacti ...

  3. springmvc mybatis 声明式事务管理回滚失效,(checked回滚)捕捉异常,传输错误信息

    一.知识点及问题 后端框架: Spring .Spring mvc .mybatis 业务需求: client先从服务端获取用户大量信息到client,编辑完毕之后统一Post至服务端,对于数据的改动 ...

  4. Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

  5. Spring事务异常回滚,捕获异常不抛出就不会回滚

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

  6. 【转】Spring事务异常回滚,捕获异常不抛出就不会回滚

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......     为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异 ...

  7. Spring事务异常回滚

    最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了.......    为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...

  8. Spring3声明式事务处理事务无法回滚rollback分析(annotation与xml配置混用)

    新项目试运行,DBA提示生产数据库一个表的事务20分钟都未提交,分析过程如下: 1.查看日志log文件,最近20分钟是否有error日志: 2.发现某表有insert错误日志,初步判断由该表插入异常, ...

  9. spring事务没回滚

    最近遇见一个问题,用spring管理实务,在service层处理数据,保存数据时出现异常,但没有回滚,检查了一下,发现是因为我用try catch将异常进行捕获了,没有抛出导致的:默认spring事务 ...

随机推荐

  1. Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap

    网上也有好多方法我没有试成功,不过我将maven的conf setting.xml里的 阿里镜像给注释就可以了,你们也可以试试

  2. Pyhton基础知识(一)

    Pyhton基础知识(一)一.cpu 内存 硬盘 操作系统之间的关系1.cpu 中央处理器 运算中心与控制中心 相当于人的大脑.2.内存 暂时存储数据 将应用程序加载到内存 以便于cpu进行数据传输交 ...

  3. windows server 2012 本地用户和组

  4. python程序化交易神器——tushare

    一直想试着将自己的交易思路程序化,可惜困难重重 ,连第一步获取数据都要花很多精力,直到最近发现了Tushare,不仅使用非常便利,功能也无比强大,股票.期货.基金.财经新闻,甚至电影票房等都可以非常便 ...

  5. MAC 无脑编译OpenCV

    1:准备好OpenCV 源码包 下载地址:https://opencv.org/releases.html 编译教程:https://blog.csdn.net/computerme/article/ ...

  6. uiautomator2.0的配置的两种方法

    方法一(使用在线下载的方式导入依赖): 1.首先创建项目工程,创建的项目的android_api版本要与测试的android_api版本一致(24就是24 ,不能26或者17去兼容) 2.然后就是将本 ...

  7. 使用SQL SERVER PIVOT实现行列转置

    一般我们在使用SQL语句实现行列转置时候,最常用的方法无外乎就是 case语句来实现,但是如果需要需要转置的列太多,那么case起来语句就无限庞大,十分不方便,sql server中的PIVOT就可以 ...

  8. iOS源文件工程打包

    第一步:添加开发者账号 第二步:刷新 第三步:设置证书名 第四步:Export

  9. 33.scrapy采集网站表单数据

    这几天一直都再用scrapy写网站数据采集的爬虫,这里我就选一个写过的爬虫来记录一下. 杭州造价网:http://183.129.219.195:8081/bs/hzzjb/web/list 这里出现 ...

  10. 关于时间:UTC/GMT/xST/ xDT

    UTC ,Coordinated Universal Time GMT ,Greenwich Mean Time GMT和UTC 一般来说是意义几近相同的, 不过 UTC Coordinated Un ...