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

背景

最近在看程序日志的时候,发现频繁出现 Transaction rolled back because it has been marked as rollback-only这个异常,查了很久资料才知道是什么原因导致抛出这异常的,下面解析一下;

原因字面上的意思就是:事务已回滚,因为它已被标记为仅回滚,那为什么会标记为仅回滚呢?

其实原因就是嵌套事务导致的,因为spring事务有传递性,spring默认的事务传播级别是PROPAGATION_REQUIRED,即当前上下文存在事务则用此事务,如果不存在事务则新建一个事务执行;

那么现在有A和B两个方法,这两个方法都开启了事务,A方法中调用B方法(因为都使用事务,默认的事务传播级别是PROPAGATION_REQUIRED,所以这过程中会使用同一个事务);

当执行B方法的时候,B方法抛出异常,这个时候事务就会被标记为仅回滚(因为在B方法中抛出异常,B方法这事务本该是要回滚,所以会将B方法的事务标记为rollback-only);

但是在A方法又catch到B方法抛的异常,但是A方法catch到异常后没有继续往上抛出,而是继续执行后面的代码,最后正常提交事务,那么就会抛出 Transaction rolled back because it has been marked as rollback-only这异常!(因为AB是用同一个事务,在B方法执行的时候这个事务就标记为rollback-only,然后A方法继续使用该事务,然后又执行事务提交的操作,所以最后会抛异常)

事例

public void a() {
        try {
            SysInterfaceLogSettintModel model = new SysInterfaceLogSettintModel();
            model.setInterfaceCode("code");
            model.setInterfaceName("name");
            //这里做了保存操作
            this.save(model);
            //这里调用了b方法,是另外一个service的
            roleMenuService.b();
            //执行完提交事务
        }catch (Exception e ){
        	//a方法catch了异常但是没有继续抛出,事务会提交
            e.printStackTrace();
        }
    }
   
	public void b() throws Exception {
		//b方法抛出异常
		throw new Exception("Exception");
	}

最后会抛出异常

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
	at sun.reflect.GeneratedMethodAccessor3052.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:620)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:609)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655)
	at com.dangdang.ddframe.job.executor.type.SimpleJobExecutor.process(SimpleJobExecutor.java:41)
	at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.process(AbstractElasticJobExecutor.java:207)
	at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor.access$000(AbstractElasticJobExecutor.java:47)
	at com.dangdang.ddframe.job.executor.AbstractElasticJobExecutor$1.run(AbstractElasticJobExecutor.java:186)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:108)
	at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:41)
	at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:77)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

首发链接: https://www.cnblogs.com/lingyejun/p/18125151

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当出现 "Transaction rolled back because it has been marked as rollback-only" 的异常时,通常是因为事务在某个方法中被标记为只能回滚,但后续的代码却试图提交该事务,从而导致异常的抛出。 一个例子是在方法A中捕获了方法B抛出的异常,并继续执行后续的代码,最后正常提交事务。然而,由于AB使用同一个事务,在方法B执行时,该事务会被标记为rollback-only,然后方法A继续使用该事务并执行事务提交的操作,因此最终会抛出异常。 要解决这个问题,可以在方法A中将异常继续往上抛出,而不是在catch块中处理异常,这样事务就会正确地回滚。例如,在方法A的catch块中将异常重新抛出,或者将异常声明为方法A抛出的异常之一。 另外,还可以通过在方法B中使用@Transactional注解来确保方法B在出现异常时事务正确回滚,以避免这个异常的出现。 总之,"Transaction rolled back because it has been marked as rollback-only" 异常通常是由于事务在被标记为rollback-only后继续提交引起的,可以通过将异常继续往上抛出或使用@Transactional注解来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [COS——R.log](https://download.csdn.net/download/ktc7000/4424623)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Transaction rolled back because it has been marked as rollback-only](https://blog.csdn.net/hingli/article/details/118415444)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值