1. 我对传播机制的理解
- 为什么需要传播机制?
因为事务之间可能存在相互调用,例如service业务层的方法存在相互调用,如果相互调用的方法都开启了事务(对应到springboot就是在方法上要添加@Transactional注解),那么程序需要以什么样的策略来执行事务呢?因此需要我们指定好事务传播机制,程序遇到这种情况就可以根据我们事先指定好的传播机制来执行。
2. spring其中事务传播机制
默认的事务传播机制是required,点进注解看源码:
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
3. 实验验证
3.1. NEVER
3.1.1 调用方不开启事务(不添加Transactional注解)
代码如下,在controller调用service方法,实验前id=3的用户开始的money是1000,正常情况下想把其money更新为900
代码如下:
Controller中testTransaction去调用service中的testTransaction,可以看到右侧被调用的方法上边传播机制设置的NEVER,执行后效果如下:
发现当Controller层不加Transactional注解,Service层的testTransaction方法上添加Transactional并且把传播机制设置为NEVEL后,事务并没有生效,执行完后抛出了异常,但是数据库还是写进去了。
每次做完实验记得把数据库的900还原成1000;
3.1.2 调用方开启事务(添加Transactional注解)
请求执行后可以看到直接抛出了异常, Existing transaction found for transaction marked with propagation ‘never’,说明调用方式不能有事务的,如果有就直接抛出上图种的异常,并且Service层的业务代码并没有执行,没有抛出 除以0的异常。
3.1.3 总结
NEVEL传播机制,要求调用方不能有事务,在本测试中表现就是Ctroller中的testTransaction方法上不能有事务的注解
3.2. REQUIRED
3.2.1 service层的传播机制设置为required
service层的传播机制设置为required时,无论Controller层开启或者不开启事务,结果都是如下:
3.2.2 结论
说明当被调用方开启了事务,并且传播机制是required的时,一定会以事务的方式执行,具体表现就是如上边的图示,代码抛出了异常 / by zero,同时数据库中并没有写入900,说明异常后数据回滚了。
其他的就不再一一测试了,都是一个道理,始终记住列表中说的“当前事务”指的是调用方。