spring事务的传播

2019-12-31  本文已影响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。

上一篇下一篇

猜你喜欢

热点阅读