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

翎野君發表於2024-04-09

背景

最近在看程式日誌的時候,發現頻繁出現 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

相關文章