在使用spring做事务管理时,很多人都会遇到这样一段异常:

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:718)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)

出现上面问题的场景类似下面代码这样:

ITestAService:

package com.gigamore.platform.ac.service;
import com.onlyou.framework.exception.BusinessException;
public interface ITestAService {
void testA() throws BusinessException;
}

TestAService:

package com.gigamore.platform.ac.service;  

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.gigamore.platform.base.service.impl.BaseServiceImpl;
import com.onlyou.framework.exception.BusinessException;
@Service
public class TestAService extends BaseServiceImpl implements ITestAService{
@Autowired
private TestBService testBService;
@Transactional
public void testA(){
try{
testBService.testB();
}catch(BusinessException e){
logger.info(e.getMessage());
}catch(Exception e){
logger.info(e.getMessage());
}
}
}

TestBService:

package com.gigamore.platform.ac.service;  

import java.util.Date;  

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import com.gigamore.platform.ac.entity.LoanProjectEntity;
import com.gigamore.platform.base.service.impl.BaseServiceImpl;
import com.onlyou.framework.exception.BusinessException;
@Service
public class TestBService extends BaseServiceImpl{
@Transactional
public void testB(){
LoanProjectEntity project = this.selectByPrimaryKey(LoanProjectEntity.class, "2c9483e748321d4601485e1714d31412");
project.setUpdDataTm(new Date());
this.update(project);
throw new BusinessException("抛异常");
}
}

测试用例:

@Autowired
private ITestAService testAService;
@Test
public void testA() {
testAService.testA();
}

testAService调用testBService的testB()方法,testB()方法里抛了一个BusinessException异常,但是testAService用try{}catch{}捕获异常并不往上层抛了。

看起来好像没什么问题,异常被捕获了。其实不然,在testAService调用testBService的testB()方法时,会经过一次spring事务控制切面,事务切面里本身会对testBService的testB()方法进行异常捕获: TransactionAspectSupport.invokeWithinTransaction

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}

 completeTransactionAfterThrowing(txInfo, ex)里面做了txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()),事务管理器做rollback, 把事务设置成rollback-only。 以上是testBService外层包装的事务切面做的事情。当testAService的testA()方法执行完,此时执行到testAService外层包装的事务切面,由于testA()方法执行过程没有抛出异常,所以事务正常提交,即执行的是commitTransactionAfterReturning(txInfo),事务对象txInfo对应的事务管理器进行提交事务,但事务已被设置为rollback-only,故spring对外抛出了Transaction rolled back because it has been marked as rollback-only异常。

解决办法:把TestBService的testB()方法的事务注解改成@Transactional(propagation = Propagation.NESTED),确实可以达到避免异常的效果。

【Spring】21、用spring目标对象处理Transaction rolled back because it has been marked as rollback-only的更多相关文章

  1. [转]Spring事务嵌套引发的血案---Transaction rolled back because it has been marked as rollback-only

    原文地址:https://blog.csdn.net/f641385712/article/details/80445912 1.概述 想必大家一想到事务,就想到ACID,或者也会想到CAP.但笔者今 ...

  2. Spring事务嵌套引发的问题--Transaction rolled back because it has been marked as rollback-only

    转载https://blog.csdn.net/f641385712/article/details/80445912 读了两边才找到问题

  3. “Transaction rolled back because it has been marked as rollback-only”

    spring的声明事务提供了强大功能,让我们把业务关注和非业务关注的东西又分离开了.好东西的使用,总是需要有代价的.使用声明事务的时候,一 个不小心经常会碰到“Transaction rolled b ...

  4. Transaction rolled back because it has been marked as rollback-only

    出现这种错误的原因 1.接口A 调用了接口B 2.接口B报异常了,没有在B里面进行try catch捕获 3.接口A对 接口B进行了try catch捕获 因为接口B报异常 会把当前事物A接口的事物( ...

  5. Transaction rolled back because it has been marked as rollback-only分析解决方法

    1. Transaction rolled back because it has been marked as rollback-only事务已回滚,因为它被标记成了只回滚<prop key= ...

  6. 【springcloud】Transaction rolled back because it has been marked as rollback-only

    问题: 一个ajax请求,发生系统错误,错误内容:Transaction rolled back because it has been marked as rollback-only 原因是调用的s ...

  7. Transaction rolled back because it has been marked as rollback-only 原因 和解决方案

    产生原因  , 1 serviceA 调用 serviceB 然后 B  抛出异常 ,B 所在的 事物 回滚,B 把当前可写 事物标记成 只读事物 , 2 如果 A 和B 是在 同一个事物环境,并且 ...

  8. 记一次org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only异常

    @Transactional(rollbackFor = Exception.class) @Overridepublic DubboResult<Boolean> productAddO ...

  9. springboot成神之——spring boot,spring jdbc和spring transaction的使用

    本文介绍spring boot,spring jdbc和spring transaction的使用 项目结构 依赖 application model层 mapper层 dao层 exception层 ...

随机推荐

  1. jupyter-notebook快捷键

    Jupyter Notebook 的快捷键 Jupyter Notebook 有两种键盘输入模式.编辑模式,允许你往单元中键入代码或文本:这时的单元框线是绿色的.命令模式,键盘输入运行程序命令:这时的 ...

  2. CS61A hw01

    前不久在知乎上看到CS61A 和CS61B spring18 开课的消息.上去看了一眼,发现真的不错,所有proj hw都可以本地测试!也就是说除了没有课程成绩和官方讨论区和TA解答外,这个课完全可以 ...

  3. 使用ILSpy软件反编译.Net应用程序的方法及注意事项

    今天遇到之前同事写的代码没有源码了,但是客户要在原来的基础上修改程序!好在没有做加壳处理,所以就用了ILSpy软件进行反编译!下面把步骤及遇到的问题写下来: 1.打开ILSpy软件,点击File  , ...

  4. kaldi的TIMIT实例三

    ============================================================================ MMI + SGMM2 Training &a ...

  5. JavaScript中常见的10个BUG及其修复方法

    如今网站几乎100%使用JavaScript.JavaScript看上去是一门十分简单的语言,然而事实并不如此.它有很多容易被弄错的细节,一不注意就导致BUG. 1. 错误的对this进行引用 在闭包 ...

  6. Python学习笔记【第十五篇】:Python网络编程三ftp案例练习--断点续传

    开发一个支持多用户在线的FTP程序-------------------主要是学习思路 实现功能点 1:用户登陆验证(用户名.密码) 2:实现多用户登陆 3:实现简单的cmd命令操作 4:文件的上传( ...

  7. Oracle创建表空间创建用户和用户授权

    今天要创建一个Oracle用户,然后发现sql不太记得了,然后只能再去找找资料,发现这样效率并不是很高,所以记录成博客,有需要就直接从博客复制. 下面是我简单整理的,有需要可以参考. --创建表空间 ...

  8. 几个java小例子

    比较两个字符串的值: /*------------------------比较两个字符串的值----------------------*/ String st1="hello"; ...

  9. golang实现参数可变的技巧

    Go 使用默认参数的技巧 Functional Options Pattern in Go golang中没有函数默认参数的设计,因此需要些特别的技巧来实现. 假如我们需要订购一批电脑,其中电脑配置c ...

  10. python(leetcode)-66加一问题

    给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 1: 输入 ...