Spring事务管理——回滚(rollback-for)控制
探讨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]
总结:
- Spring事务管理是根据异常来进行回滚操作;
- Spring与Mybatis整合时,虽然在Service方法中并没有check异常,但是如果数据库有异常发生,默认会进行事务回滚。
- Spring 如果不添加rollbackFor等属性,Spring碰到Unchecked Exceptions都会回滚,不仅是RuntimeException,也包括Error。
- 如果在事务方法中捕获异常并进行处理,一定要继续抛出异常并在Spring事务管理中进行rollbak-for配置。
转自:https://blog.csdn.net/ljyhust/article/details/73431968?locationNum=5&fps=1
Spring事务管理——回滚(rollback-for)控制的更多相关文章
- Spring事务管理回滚问题
Spring事务管理不能回滚问题 在前段时间学习SpringMVC的练习中,碰到声明式事务管理时,事务不能回滚的情况,通过查看博客和资料,解决了问题. 原因 导致Spring事务管理不能回滚的原因有两 ...
- Spring事务不回滚原因分析
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离. 在我完成一个项目的时候,遇到了一个Spring事务不回滚的问题,通过aspectJ和@Transacti ...
- springmvc mybatis 声明式事务管理回滚失效,(checked回滚)捕捉异常,传输错误信息
一.知识点及问题 后端框架: Spring .Spring mvc .mybatis 业务需求: client先从服务端获取用户大量信息到client,编辑完毕之后统一Post至服务端,对于数据的改动 ...
- Spring事务异常回滚,捕获异常不抛出就不会回滚(转载) 解决了我一年前的问题
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...
- Spring事务异常回滚,捕获异常不抛出就不会回滚
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...
- 【转】Spring事务异常回滚,捕获异常不抛出就不会回滚
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异 ...
- Spring事务异常回滚
最近遇到了事务不回滚的情况,我还考虑说JPA的事务有bug? 我想多了....... 为了打印清楚日志,很多方法我都加tyr catch,在catch中打印日志.但是这边情况来了,当这个方法异常 ...
- Spring3声明式事务处理事务无法回滚rollback分析(annotation与xml配置混用)
新项目试运行,DBA提示生产数据库一个表的事务20分钟都未提交,分析过程如下: 1.查看日志log文件,最近20分钟是否有error日志: 2.发现某表有insert错误日志,初步判断由该表插入异常, ...
- spring事务没回滚
最近遇见一个问题,用spring管理实务,在service层处理数据,保存数据时出现异常,但没有回滚,检查了一下,发现是因为我用try catch将异常进行捕获了,没有抛出导致的:默认spring事务 ...
随机推荐
- Eclipse使用Maven创建Web时错误:Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webap
网上也有好多方法我没有试成功,不过我将maven的conf setting.xml里的 阿里镜像给注释就可以了,你们也可以试试
- Pyhton基础知识(一)
Pyhton基础知识(一)一.cpu 内存 硬盘 操作系统之间的关系1.cpu 中央处理器 运算中心与控制中心 相当于人的大脑.2.内存 暂时存储数据 将应用程序加载到内存 以便于cpu进行数据传输交 ...
- windows server 2012 本地用户和组
- python程序化交易神器——tushare
一直想试着将自己的交易思路程序化,可惜困难重重 ,连第一步获取数据都要花很多精力,直到最近发现了Tushare,不仅使用非常便利,功能也无比强大,股票.期货.基金.财经新闻,甚至电影票房等都可以非常便 ...
- MAC 无脑编译OpenCV
1:准备好OpenCV 源码包 下载地址:https://opencv.org/releases.html 编译教程:https://blog.csdn.net/computerme/article/ ...
- uiautomator2.0的配置的两种方法
方法一(使用在线下载的方式导入依赖): 1.首先创建项目工程,创建的项目的android_api版本要与测试的android_api版本一致(24就是24 ,不能26或者17去兼容) 2.然后就是将本 ...
- 使用SQL SERVER PIVOT实现行列转置
一般我们在使用SQL语句实现行列转置时候,最常用的方法无外乎就是 case语句来实现,但是如果需要需要转置的列太多,那么case起来语句就无限庞大,十分不方便,sql server中的PIVOT就可以 ...
- iOS源文件工程打包
第一步:添加开发者账号 第二步:刷新 第三步:设置证书名 第四步:Export
- 33.scrapy采集网站表单数据
这几天一直都再用scrapy写网站数据采集的爬虫,这里我就选一个写过的爬虫来记录一下. 杭州造价网:http://183.129.219.195:8081/bs/hzzjb/web/list 这里出现 ...
- 关于时间:UTC/GMT/xST/ xDT
UTC ,Coordinated Universal Time GMT ,Greenwich Mean Time GMT和UTC 一般来说是意义几近相同的, 不过 UTC Coordinated Un ...