美文网首页
spring事务的传播

spring事务的传播

作者: 大风过岗 | 来源:发表于2019-12-31 21:10 被阅读0次

    前置问题

    问题1:spring生成了几个逻辑事务?testTx会回滚吗? method2的事务会生效吗 ?

     @Override
        public void testTx() {
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            method2();
        }
    
        @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
        public void method2(){
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试method2"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
           throw new RuntimeException("运行时异常");
        }
    

    问题2: 此时spring生成了几个逻辑事务? method2的事务会生效吗 ?

      @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
        @Override
        public void testTx() {
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            method2();
        }
    
        @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
        public void method2(){
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试method2"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            throw new RuntimeException("运行时异常");
        }
    
    

    问题3: 问此时有几个逻辑事务? 方法testTx会回滚吗?

    @Service
    public class TransactionTxServiceImpl implements TransactionTxService {
    
        @Autowired
        private WechatPayCallbackLogMapper wechatPayCallbackLogMapper;
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void method2(){
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试method2");
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            throw new RuntimeException("异常");
        }
    
    }
    
    
    @Service
    public class TransactionServiceImpl implements TransactionService {
    
    
        @Autowired
        private WechatPayCallbackLogMapper wechatPayCallbackLogMapper;
    
        @Autowired
        private TransactionTxService  transactionTxService;
    
        @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
        @Override
        public void testTx() {
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            transactionTxService.method2();
        }
    
    }
    
    
    

    问题4: 此时有几个逻辑事务? 有几个物理事务? testTx会回滚吗?

    @Service
    public class TransactionTxServiceImpl implements TransactionTxService {
    
        @Autowired
        private WechatPayCallbackLogMapper wechatPayCallbackLogMapper;
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void method2(){
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试method2");
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            throw new RuntimeException("异常");
        }
    
    }
    
    
    

    代码:

    @Service
    public class TransactionServiceImpl implements TransactionService {
    
    
        @Autowired
        private WechatPayCallbackLogMapper wechatPayCallbackLogMapper;
    
        @Autowired
        private TransactionTxService  transactionTxService;
    
        @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
        @Override
        public void testTx() {
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            transactionTxService.method2();
        }
    
    }
    
    
    

    问题5: 此时testTx方法会回滚吗?

    @Service
    public class TransactionTxServiceImpl implements TransactionTxService {
    
        @Autowired
        private WechatPayCallbackLogMapper wechatPayCallbackLogMapper;
    
        @Transactional(propagation = Propagation.REQUIRED)
        public void method2(){
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试method2");
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
            throw new RuntimeException("异常");
        }
    
    }
    
    
    

    代码:

    @Service
    public class TransactionServiceImpl implements TransactionService {
    
    
        @Autowired
        private WechatPayCallbackLogMapper wechatPayCallbackLogMapper;
    
        @Autowired
        private TransactionTxService  transactionTxService;
    
        @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
        @Override
        public void testTx() {
            WechatPayCallbackLog log = new WechatPayCallbackLog();
            log.setOrderType(9);
            log.setOrderId(2L);
            log.setOrderNum("测试"+RandomUtils.randomString(2));
            log.setMchId(RandomUtils.randomString(3));
            log.setAppId(RandomUtils.randomString(3));
            log.setCompanyId(1l);
            log.setCompanyName(RandomUtils.randomString(3));
            log.setNotifyContent(RandomUtils.randomString(20));
            log.setCreateTime(new Date());
            wechatPayCallbackLogMapper.insert(log);
           try{
             transactionTxService.method2();
           }catch(Exception e){
             e.printStackTrace();
           }
           
        }
    
    }
    
    
    

    spring事务代理

    txProxyCall.png

    spring支持俩种代理模式: springAOP 和AspectJ。spring声明式事务的底层默认是通过AOP代理来实现的,spring会为事务方法生成一个事务代理对象,最终的调用执行的是代理对象的事务方法。
    即:
    spring会为那些声明了@Transactional注解的类或含有@Transactional注解的方法生成代理对象,这个代理对象会实现了被注解类的所有方法,同时在事务方法的前后织入事务相关的代码。当有客户端调用被注解类的对象的方法时,spring的事务拦截器TransactionalInterceptor会拦截住此调用,该事务拦截器会调用对应的事务代理对象的目标方法,从而执行commit或roll back操作。

    所以: 只有该对象的事务方法在该对象外部被调用时,才会走代理,从而调用代理对象的相应方法,在本对象内部调用本对象内的方法,不会走代理。比如this.methodxxx()这种调用的还是对象本身的方法。

    关于这一点的讨论,可以参荐stackOverflow:@Transactional注解背后的执行原理

    spring的事务传播

    请注意这里讲的仅仅是spring中的事务传播机制。

    在spring管理的事务中,需要明白物理事务和逻辑事务的差别,以及事务的传播设置是如何应用到它们上去的。

    PROPAGATION_REQUIRED

    tx_prop_required.png

    当事务的传播设置为 PROPAGATION_REQUIRED时,那么spring就会为每个方法创建一个逻辑事务。在外层事务逻辑上与内部事务互相独立时, 每个逻辑事务都能独立修改rollback-only的状态。在PROPAGATION_REQUIRED的情况下,这些的逻辑事务都将被映射到同一个物理事务上。故而,内层事务如果修改了rollback-only标记的话,确实会对外层事务的提交产生影响。

    但是,如果在内层事务设置了rollback-only标记的情况下,外层事务自己并没有显示地进行回滚操作。它是由内层事务自己触发的。因此,这种回滚操作并不是我们期望的。此时会抛出一个UnexpectedRollbackException异常。
    这是我们期望的行为。因为这样的话,事务的调用者就不会误以为执行了commit操作。所以,当内层事务在外层事务不知道的情况下把事务标记为rollback-only情况下,如果外层事务仍然执行commit操作的话,就会得到一个UnexpectedRollbackException异常。这个异常表明了已经执行了回滚操作。

    PROPAGATION_REQUIRES_NEW

    tx_prop_requires_new.png

    相比之下,PROPAGATION_REQUIRES_NEW则会为每一个受影响的事务域创建一个完全独立的事务。在这种情况下,每个独立的逻辑事务底层都对应一个单独的物理事务。因此,他们提交和回滚操作都是各自独立的。此时,内部事务的rollback状态丝毫不会对外层事务造成影响。

    PROPAGATION_NESTED

    PROPAGATION_NESTED内部使用的是具有多个保存点的单个物理事务(保存点就是用于回滚操作的)。这种部分回滚使得当一个内部事务触发它自己的回滚操作时,外部事务可以继续执行物理事务,尽管
    有一些操作被回滚了。 这种设置通常都是和JDBC的保存点相对应,所以仅仅适用于JDBC事务。详情可看spring的DataSourceTransactionManager。

    相关文章

      网友评论

          本文标题:spring事务的传播

          本文链接:https://www.haomeiwen.com/subject/bgtmoctx.html