简介
SpringBoot中默认对jpa,jdbc,mybatis开启了事务处理,只需要在使用事务的类或者方法上增加@Transactional注解即可.
参数介绍
org.springframework.transaction.annotation.Transactional
注解参数
所有参数都为可选,spring已提供默认值
参数名称 | 类型 | 说明 |
value | String | 对应事务管理器的名称 |
propagation | Propagation枚举 | 事务传播行为设置,默认为Propagation.REQUIRED |
isolation | Isolation枚举 | 事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
timeout | int (秒) | 事务超时时间设置,默认为-1,即不限制 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自Throwable | 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组,必须继承自Throwable | 不会导致事务回滚的异常类名字数组 |
Propagation枚举:
类型 | 说明 |
Propagation.REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
Propagation.SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
Propagation.MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
Propagation.REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。新建的事务与外部事务无关联 |
Propagation.NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
Propagation.NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
Propagation.NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION.REQUIRED类 似的操作。 |
PROPAGATION_REQUIRES_NEW 与PROPAGATION_NESTED 的区别
- PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
- PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.
- 由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
Isolation枚举:
类型 | 说明 |
Isolation.DEFAULT | 使用数据库默认的事务隔离级别 |
Isolation.READ_UNCOMMITTED | 允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读。 |
Isolation.READ_COMMITTED | 允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。 |
Isolation.REPEATABLE_READ | 对相同字段的多次读取结果一致,可能导致幻读 |
Isolation.SERIALIZABLE | 完全服从ACID的原则,确保不发生脏读、不可重复读和幻读 |
- 脏读:修改且未提交引起,事务A读取到了另一个事务B还没有提交的数据,并在此基础上进行操作。如果B事务rollback,那么A事务所读取到的数据就是不正确的,会带来问题。
- 幻读:修改引起,在同一事务范围内读取两次相同的数据,所返回的结果不同。比如事务B第一次读数据后,事务A更新数据并commit,那么事务B第二次读取的数据就与第一次是不一样的。
- 不可重复读:添加新记录引起,事务A读取到了另一个事务B新提交的数据。比如,事务A对一个表中所有行的数据按照某规则进行修改(整表操作),同时,事务B向表中插入了一行原始数据,那么后面事务A再对表进行操作时,会发现表中居然还有一行数据没有被修改。
注意事项:
- @Transactional仅会回滚RuntimeException和Error类的异常,但可通过rollbackFor来扩展回滚对应异常
- 如手动捕获异常并没有相应的处理数据依然不会回滚
- javax 和 spring都有Transactional注解。但参数不一样
- @Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
- 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
参考资料
https://blog.csdn.net/Mint6/article/details/78363761
https://www.cnblogs.com/yepei/p/4716112.html
http://www.iteye.com/topic/35907/
https://blog.csdn.net/soonfly/article/details/70305585
http://xiezhaodong.me/2017/01/15/MySQL%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E5%92%8CSpring%E4%BA%8B%E5%8A%A1%E5%85%B3%E7%B3%BB%E4%BB%8B%E7%BB%8D/
https://zhuanlan.zhihu.com/p/27887568
https://www.cnblogs.com/yldIndex/p/spring_Transactional.html