一. 声明式注解与编程式事务
1.1 说明
- 声明式事务通过手动注解或xml配置的方式, 通过spring来管理事务. 声明式事务属于无侵入式,不会影响业务逻辑的实现. 是spring推荐的, 也是主流做法.
- 编程式事务需要手动开启, 手动控制回滚, 手动提交. 且每次重新实现. spring并不推荐.
1.2 从编程式事务改造成声明式事务
二. 事务怎么加, 什么时候会失效 ?
事务加到哪里? controller层, service层, dao层, 还是都加? 加到方法上还是加到类上? 加了为什么会失效?
2.1 建议
- 在事务执行之前, 事务逻辑无关的数据准备好,比如流水号, 待更新的库存量, 字典数据.
- 把事务管理的多个SQL封装到一个方法. 放在dao层. 给该方法加上@Transaction
- 让事务逻辑尽量短小精悍 🙃
2.2 事务失效的常见原因
2.2.1 方法内部调用
1 |
|
此时 controller 调用 updateTable3 事务是生效的
如果由 updateTable4 调用 updateTable3 方法. 此时 updateTable3 的事务是失效了.
这是因为 updateTable3 方法拥有事务的能力是因为 spring 生成了 updateTable3 的代理对象. 直接调用 this 对象的方式就失效了.
2.2.2 被private修饰
1 |
|
这个好理解. spring 要求方法必须为 public
2.2.3 异常被异常处理了
1 |
|
注意:
1. 捕获异常之后需要再次抛出 runtimeException, 不然 spring 认为没有异常.
2. 抛出 Exception 同理. spring 也不会回滚
三. 事务的传播行为 @Transactional(propagation = Propagation.REQUIRED)
一共有7个. 可以网上查阅.
这里总结工作中遇到的2个.
3.1 REQUIRED
- 全部成功才提交. 也是默认值. 为了保证数据完整性. 所有sql执行完成才提交数据.
3.2 REQUIRES_NEW
- 新建事务, 执行成功先提交, 当前存在事务, 新建事务执行异常则回滚外部事务
- 一般是请求外部接口时会用到, 比如我们请求三方数据, 对方返回了消息. 程序应该优先把数据保存到数据库. 后续逻辑不应该影响消息回写.