前置问题
问题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事务代理
![](https://img.haomeiwen.com/i13084796/f839acd48df57e7c.png)
spring支持俩种代理模式: springAOP 和AspectJ。spring声明式事务的底层默认是通过AOP代理来实现的,spring会为事务方法生成一个事务代理对象,最终的调用执行的是代理对象的事务方法。
即:
spring会为那些声明了@Transactional注解的类或含有@Transactional注解的方法生成代理对象,这个代理对象会实现了被注解类的所有方法,同时在事务方法的前后织入事务相关的代码。当有客户端调用被注解类的对象的方法时,spring的事务拦截器TransactionalInterceptor会拦截住此调用,该事务拦截器会调用对应的事务代理对象的目标方法,从而执行commit或roll back操作。
所以: 只有该对象的事务方法在该对象外部被调用时,才会走代理,从而调用代理对象的相应方法,在本对象内部调用本对象内的方法,不会走代理。比如this.methodxxx()这种调用的还是对象本身的方法。
关于这一点的讨论,可以参荐stackOverflow:@Transactional注解背后的执行原理
spring的事务传播
请注意这里讲的仅仅是spring中的事务传播机制。
在spring管理的事务中,需要明白物理事务和逻辑事务的差别,以及事务的传播设置是如何应用到它们上去的。
PROPAGATION_REQUIRED
![](https://img.haomeiwen.com/i13084796/bc69bee8a3771020.png)
当事务的传播设置为 PROPAGATION_REQUIRED时,那么spring就会为每个方法创建一个逻辑事务。在外层事务逻辑上与内部事务互相独立时, 每个逻辑事务都能独立修改rollback-only的状态。在PROPAGATION_REQUIRED的情况下,这些的逻辑事务都将被映射到同一个物理事务上。故而,内层事务如果修改了rollback-only标记的话,确实会对外层事务的提交产生影响。
但是,如果在内层事务设置了rollback-only标记的情况下,外层事务自己并没有显示地进行回滚操作。它是由内层事务自己触发的。因此,这种回滚操作并不是我们期望的。此时会抛出一个UnexpectedRollbackException异常。
这是我们期望的行为。因为这样的话,事务的调用者就不会误以为执行了commit操作。所以,当内层事务在外层事务不知道的情况下把事务标记为rollback-only情况下,如果外层事务仍然执行commit操作的话,就会得到一个UnexpectedRollbackException异常。这个异常表明了已经执行了回滚操作。
PROPAGATION_REQUIRES_NEW
![](https://img.haomeiwen.com/i13084796/8e7d02a48b74ffba.png)
相比之下,PROPAGATION_REQUIRES_NEW则会为每一个受影响的事务域创建一个完全独立的事务。在这种情况下,每个独立的逻辑事务底层都对应一个单独的物理事务。因此,他们提交和回滚操作都是各自独立的。此时,内部事务的rollback状态丝毫不会对外层事务造成影响。
PROPAGATION_NESTED
PROPAGATION_NESTED内部使用的是具有多个保存点的单个物理事务(保存点就是用于回滚操作的)。这种部分回滚使得当一个内部事务触发它自己的回滚操作时,外部事务可以继续执行物理事务,尽管
有一些操作被回滚了。 这种设置通常都是和JDBC的保存点相对应,所以仅仅适用于JDBC事务。详情可看spring的DataSourceTransactionManager。
网友评论