在使用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. all about

    1.三次握手和四次挥手?2.什么是OSI七层结构?3.http vs https?4.what is Ping?基于什么协议?使用方法?5.DNS?6.cookie vs session?7.LDAP ...

  2. 在ASP.NET MVC里对Web Page网页进行权限控制

    我们在ASP.NET MVC开发时,有时候还是得设计ASP.NET的Web Page网页(.aspx和.aspx.cs),来实现一些ASP.NET MVC无法实现的功能,如此篇<Visual S ...

  3. 在Spring-Boot中实现通用Auth认证的几种方式

    code[class*="language-"], pre[class*="language-"] { background-color: #fdfdfd; - ...

  4. 【高速接口-RapidIO】1、RapidIO协议概述

    一.RapidIO背景介绍 RapidIO是由Motorola和Mercury等公司率先倡导的一种高性能. 低引脚数. 基于数据包交换的互连体系结构,是为满足和未来高性能嵌入式系统需求而设计的一种开放 ...

  5. express使用记录

    express使用记录 文章用啥写?→→ VsCode. 代码用啥写?→→ VsCode. 编辑器下载:VsCode 一.windows下安装node.js环境: 下载地址 相比以前搭过的服务端语言的 ...

  6. elasticSearch新认知

    之前已经学习使用过ElasticSearch的使用,今天补充巩固一下... 上一次的环境是在 linux下使用 EalsticSearch(安装教程详见:https://www.cnblogs.com ...

  7. python多线程在渗透测试中的应用

    难易程度:★★★ 阅读点:python;web安全; 文章作者:xiaoye 文章来源:i春秋 关键字:网络渗透技术 前言 python是门简单易学的语言,强大的第三方库让我们在编程中事半功倍,今天, ...

  8. 空手套白狼,硬阅java字节码class文件

    如下,是一些java字节码也就是原始的class文件,当应用部署到线上之后,我们能够看到的也就是这样的字样了.那么怎样解呢?就让我们一起,来解读解读字节码吧! Offset A B C D E F C ...

  9. Python爬虫-萌妹子图片

    最近发现一个可以看图的地方,一张张翻有点累,毕竟只有一只手(难道鼠标还能两只手翻?).能不能下到电脑上看呢,毕竟不用等网速,还可以预览多张,总之很方便,想怎么就怎么,是吧? 刚好这几天在学python ...

  10. 使用opencv库编译代码并运行

    安装Opencv之后,首先要写一份代码测试一下是否ok. 本文代码图像边沿检测的: #include <opencv2/highgui/highgui.hpp> #include < ...