spring声明式事务总结

  1. 在spring框架下,一般使用注解@Transactional,在一个bean的方法头声明此方法中的对数据库的操作处于一个事务中,比如
    @Transactional(rollbackFor = Exception.class)
    public void testAInsert() throws Exception {

  2. 在注解中可以用rollbackFor标注遇到哪种Throwable,比如Exception,那么遇到Exception及其子类异常都会导致此事务回滚

  3. 声明式事务实际上将事务的开启、提交、回滚全都交给了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("抛个异常");
    }
  1. 反之,如果a()本身受spring事务管理,再去调用b(),b执行完数据库操作后抛个异常,由于他们实际处于同一事务中,这时还是要看在a方法中如何处理这个异常:如果直接也往外面抛,那么整个事务回滚,包括b方法中对数据库的操作;如果在a方法中catch住不抛出去,实际上等于吞掉了异常,对于spring事务管理来说感知不到有异常发生,因此事务完整提交

  2. 再来对于两个service中的两个方法调用,比如Servicea.a()方法,简称a方法,serviceb.b()方法,简称b方法.仍然先看a方法未声明事务,调用b声明事务方法,由于a方法调用的时候是用serviceb.b()来调用,而serviceb这个bean受spring管理,spring事务能够在此方法调用前后做增强,因此b方法事务生效

  3. 反过来,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

  1. 当a方法和b方法都声明事务,但是propagation = Propagation.REQUIRED时,由于还是同一事务中,跟第六点一样
  2. 当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("抛个异常");
    }
  1. 当a方法声明事务,b方法声明事务且为级联事务时propagation = Propagation.REQUIRES_NEW,相当于b()中开启新事务,两个事务之间相互不影响,所以当b事务本身发生异常回滚后,a事务仍然可以提交不受影响,当然前提是b中的异常没有扩散到a,使得a方法也抛异常,反之a的回滚也不影响b事务

你可能感兴趣的:(开发总结)