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