spring,springboot之事务(事务传播机制详解、嵌套事务)

事务传播机制:

事务的传播行为是针对嵌套事务而言。即是针对(需要事务的业务方法)调用(需要事务的业务方法)。
** 注意事项:
以下案例的业务方法在不同的类下:
在同一个类下面不同的方法就算都有事务,调用的方法事务都是不会生效的。
意思是在A类的a方法调用b方法,a,b方法均有事务,直接调用b方法,事务是不会生效的。
原因是spring事务处理实际是基于动态代理生成类进行事务管理的,而直接调用b方法,调用的实际是当前类的b方法,而并非是代理类的方法,所以b方法并不能加入事务处理。**
解决方法有很多:
①:可以在当前类注入被spring管理的bean
之前直接调用

this.b()

之后先注入 A类, 最后以a.b()方式调用,事务即可生效。

@Autowired
 private A a;
 a.b()

②:利用aop获取当前的代理对象

AopContext.currentProxy() 

回归正题。。。
@Transactional

1:REQUIRED

spring的默认传播行为。
作用:
** 支持事务,如果业务方法执行时在一个事务中,则加入当前事务,否则则重新开始一个事务。
外层事务提交了,内层才会提交。
内/外只要有报错,他俩会一起回滚。(栗子二,三)
只要内层方法报错抛出异常,即使外层有try-catch,该事务也会回滚!(栗子一)
内层不存在事务,外层存在事务,即加入外层的事务,不管内层,外层报错,都会回滚事务。**
栗子一:
条件:外层正常try-catch内层,内层出错。
结果:事务回滚,内层外层都回滚。
报错:

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

外层方法

//外层正常
@Service
public class UserServiceImpl implements UserService{
	@Autowired
    private TeacherService teacherService;
    
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        try {
            teacherService.add();
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }
}

内层方法

//内层出错
@Service
public class TeacherServiceImpl implements TeacherService {

    @Autowired
    private TeacherMapper teacherMapper;

    @Override
    @Transactional
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }
}

栗子二:
条件:外层正常,内层出错,外层不try-catch
结果:事务回滚,内层外层都回滚。
栗子三:
条件:外层出错,内层正常
结果:事务回滚,内层外层都回滚。

2:REQUIRES_NEW

作用:
** 支持事务。每次都是创建一个新事物,如果当前已经在事务中了,会挂起当前事务。
内层事务结束,内层就提交了,不用等着外层一起提交。
外层报错回滚,不影响内层。(栗子一)
内层报错回滚,外层try-catch内层的异常,外层不会回滚。(栗子二)
内层报错回滚,然后又会抛出异常,外层如果没有捕获处理内层抛出来的这个异常,外层还是会回滚的。(栗子三)**
栗子一:
内层正常,外层报错。
结果:内层提交,外层回滚。

//外层报错
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        teacherService.add();
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }
//内层正常
	@Transactional(propagation = Propagation.REQUIRES_NEW)
    public int add() {
        teacherMapper.add(1, 10);
        return 0;
    }

栗子二:
内层报错,外层try-catch。
结果:外层提交,内层回滚。
栗子三:
内层报错,外层不try-catch。
结果:外层回滚,内层回滚。

3:NESTED

作用:
** 支持事务。如果当前已经在一个事务中了,则嵌套在已有的事务中作为一个子事务。如果当前没在事务中则开启一个事务。
内层事务结束,要等着外层一起提交。
外层回滚,内层也回滚。(栗子一)
如果只是内层回滚,影响外层。(栗子二)[因为默认成为了子事务]
如果只是内层回滚,外层try-catch内层的异常,不影响外层。(栗子三)
这个内层回滚不影响外层的特性是有前提的,否则内外都回滚。**
前提:
**1.JDK版本要在1.4以上,有java.sql.Savepoint。因为nested就是用savepoint来实现的。
2.事务管理器的nestedTransactionAllowed属性为true。
3.外层try-catch内层的异常。
**
栗子一:
内层正常,外层报错。
结果:内层回滚,外层回滚。

//外层报错
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        teacherService.add();
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }
//内层正常
	@Transactional(propagation = Propagation.NESTED)
    public int add() {
        teacherMapper.add(1, 10);
        return 0;
    }

栗子二:
内层报错,外层正常。
结果:内层回滚,外层回滚。
栗子三:
内层报错,外层正常try /catch 内层。
结果:内层回滚,外层提交。

//外层正常
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        try {
            teacherService.add();
        }catch (Exception e){
        }
        return 0;
    }
//内层报错
	@Transactional(propagation = Propagation.NESTED)
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }

事务管理器配置

@Configuration
public class TransactionConfig {
    @Bean
    public PlatformTransactionManager txManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
        dataSourceTransactionManager.setNestedTransactionAllowed(true);
        return dataSourceTransactionManager;
    }
}

4:SUPPORTS

作用:
** 支持事务。当前有事务就加入当前事务。当前没有事务就算了,不会开启一个事物。**
栗子一:
外层正常有事务,内层报错。
结果:外层回滚,内层回滚。

//外层正常
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        teacherService.add();
        return 0;
    }
//内层报错
	@Transactional(propagation = Propagation.SUPPORTS)
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }

栗子二:
外层正常有事务try/catch,内层报错。
结果:外层回滚,内层回滚。
栗子三:
外层报错有事务,内层正常。
结果:外层回滚,内层回滚。
栗子四:
外层正常无事务,内层报错。
结果:外层提交,内层提交。

5:MANDATORY

作用:
** 支持事务,如果业务方法执行时已经在一个事务中,则加入当前事务。否则抛出异常。**
栗子一:
外层正常有事务,内层报错。
结果:外层回滚,内层回滚。

//外层正常
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        teacherService.add();
        return 0;
    }
//内层报错
	@Transactional(propagation = Propagation.MANDATORY)
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }

栗子二:
外层正常无事务,内层报错。
结果:外层提交,内层回滚。
报错

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

6:NOT_SUPPORTED

作用:
** 不支持事务,如果业务方法执行时已经在一个事务中,则挂起当前事务,等方法执行完毕后,事务恢复进行。**
栗子一:
外层正常有事务,内层报错。
结果:外层回滚,内层提交。

//外层正常
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        teacherService.add();
        return 0;
    }
//内层报错
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }

栗子二:
外层正常有事务try/catch内层,内层报错。
结果:外层提交,内层提交。

//外层正常
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        try {
            teacherService.add();
        }catch (Exception e){
       
        }
        return 0;
    }
//内层报错
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }

7:NEVER

作用:
** 不支持事务。如果当前已经在一个事务中了,抛出异常。数据回滚。**
栗子一:
外层正常有事务,内层报错。
结果:外层回滚,内层回滚。

//外层正常
    @Transactional(rollbackFor = {Exception.class})
    public int transaction() {
        userMapper.add(3, 200D);
        teacherService.add();
        return 0;
    }
//内层报错
	@Transactional(propagation = Propagation.NEVER)
    public int add() {
        teacherMapper.add(1, 10);
        int x = 10; if(x == 10) throw new RuntimeException("出错啦!");
        return 0;
    }

报错

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

栗子二:
外层正常无事务,内层报错。
结果:外层提交,内层提交。
栗子三:
外层报错有事务,内层正常。
结果:外层回滚,内层回滚。

你可能感兴趣的:(java)