- 在spring框架下,一般使用注解@Transactional,在一个bean的方法头声明此方法中的对数据库的操作处于一个事务中,比如
@Transactional(rollbackFor = Exception.class)
public void testAInsert() throws Exception { - 在注解中可以用rollbackFor标注遇到哪种Throwable,比如Exception,那么遇到Exception及其子类异常都会导致此事务回滚
- 声明式事务实际上将事务的开启、提交、回滚全都交给了spring管理,原理就是spring代理的类增强,因此如果在Class A中的普通方法a(),调用了事务方法b(),实际上相当于调用this.b(),由于a()本身不受spring事务管理,实际上就是普通方法调用,因此不会开启事务
// @Transactional(rollbackFor = Exception.class)
public void testAInsert() throws Exception {
TestA testA = new TestA();
testA.setName("a");
testAMapper.insertSelective(testA);
// testBInsert();
try {
testBInsert();
}catch (Exception e){
}
}
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testBInsert() throws Exception {
TestB testB = new TestB();
testB.setName("b");
testBMapper.insertSelective(testB);
throw new Exception("抛个异常");
}
- 反之,如果a()本身受spring事务管理,再去调用b(),b执行完数据库操作后抛个异常,由于他们实际处于同一事务中,这时还是要看在a方法中如何处理这个异常:如果直接也往外面抛,那么整个事务回滚,包括b方法中对数据库的操作;如果在a方法中catch住不抛出去,实际上等于吞掉了异常,对于spring事务管理来说感知不到有异常发生,因此事务完整提交
- 再来对于两个service中的两个方法调用,比如Servicea.a()方法,简称a方法,serviceb.b()方法,简称b方法.仍然先看a方法未声明事务,调用b声明事务方法,由于a方法调用的时候是用serviceb.b()来调用,而serviceb这个bean受spring管理,spring事务能够在此方法调用前后做增强,因此b方法事务生效
- 反过来,a方法声明事务,b方法普通方法,让b方法抛异常后,在a方法中吞掉,这时由于b方法处于a方法事务的事务开启之后,提交之前,等于他们处于同一方法中,所以b抛出的异常让spring事务感知到,引发了此事务回滚,标记为readonly,即使在a方法中catch异常吞掉,原来的事务仍然被回滚,这时候会报一个:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
- 当a方法和b方法都声明事务,但是propagation = Propagation.REQUIRED时,由于还是同一事务中,跟第六点一样
- 当a方法声明事务,b方法声明事务且为级联事务时propagation = Propagation.NESTED,级联事务相当于在原来的事务中开启一个子事务,受主事务影响,随着主事务的回滚提交一起进行,但是当子事务本身发生异常回滚后,主事务仍然可以提交不受影响,当然前提是b中的异常没有扩散到a,使得a方法也抛异常
@Transactional(rollbackFor = Exception.class)
public void testAInsert() throws Exception {
TestA testA = new TestA();
testA.setName("a");
testAMapper.insertSelective(testA);
// testBInsert();
try {
serviceB.testBInsert();
}catch (Exception e){
}
}
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testBInsert() throws Exception {
TestB testB = new TestB();
testB.setName("jun");
testBMapper.insertSelective(testB);
throw new Exception("抛个异常");
}
- 当a方法声明事务,b方法声明事务且为级联事务时propagation = Propagation.REQUIRES_NEW,相当于b()中开启新事务,两个事务之间相互不影响,所以当b事务本身发生异常回滚后,a事务仍然可以提交不受影响,当然前提是b中的异常没有扩散到a,使得a方法也抛异常,反之a的回滚也不影响b事务