zoukankan      html  css  js  c++  java
  • 【Spring】21、用spring目标对象处理Transaction rolled back because it has been marked as rollback-only

     在使用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),确实可以达到避免异常的效果。

  • 相关阅读:
    横竖屏判断及禁止浏览器滑动条
    sinablog to cnblogs
    qml 3d 纪念那些曾经爬过的坑
    opencv 学习一安装环境vs2015+opencv3
    vs2015 调试 无法启动程序
    qtableview 表格风格设置
    qt 给父窗体设置样式不影响子控件样式以及子控件设置透明
    Qt ASSERT:"QMetaObjectPrivate::get(smeta)->revision>= 7"in file kernelqobject.cpp,line 2646
    cmake 学习-cmakelists.txt
    CMake学习- 使用批处理设置编译环境
  • 原文地址:https://www.cnblogs.com/wangzhongqiu/p/7241058.html
Copyright © 2011-2022 走看看