两种方式
在细粒度控制和易用性之间进行权衡
- 编码式事务:精准控制事务边界
- 声明式事务:方法级,通过使用AOP实现,通过事务属性来定义
其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
spring事务传播
class ServiceA {
public void methodOutter(){
//statements XXXXXX,savepoint
ServiceB ss = new ServiceB();
ss.methodInner();
//statements XXXXXX
}
}
class ServiceB{
public void methodInner(){
}
}
- propagation_mandatory
方法必须在事务中运行,如果事务不存在,会抛出异常
只能被父事务调用 - propagation_required
当前方法必须运行在事务中:
如果当前事务存在,方法在该事务中运行;否则,启动一个新的事务
ServiceA中的methodOutter已经起了事务,这时再单独调ServiceB中的methodInner,不会再起新的事务,与ServiceA中共用一个事务。无论两个方法哪个发生异常,都会一起回滚 - propagation_requires_new
方法必须运行在自己的事务中:上述场景中,
先挂起methodOutter所在的事务;
methodInner会启动一个新的事务;
methodInner事务完成后,再继续执行methodOutter
与required的重要区别:如果ServiceB中的methodInner已经提交,ServiceA中的methodOutter失败回滚是不会影响ServiceB的 - propagation_nested
比如上面的代码,ServiceB.methodInner是ServiceA.methodOutter的一个子事务,在执行ServiceB.methodInner时会取得一个savepoint,如果ServiceB.methodInner失败,会回滚到savepoint。
ServiceB.methodInner的事务会在ServiceA.methodOutter结束后才会被提交
外部事务回滚,嵌套事务也会回滚 - propagation_supports
如果当前在事务中,就以事务的形式运行;否则以非事务的形式运行 - propagation_notSupported
比如ServiceA.methodOutter是required,ServiceB.methodInner是notSupported,当执行ServiceB.methodInner时,会挂起ServiceA.methodOutter,以非事务形式执行完ServiceB.methodInner,再以事务形式执行A - propagation_never
对比notSupported,当执行到ServiceB.methodInner,会抛出异常
顺便记一下数据库事务的隔离级别
隔离级别 | 产生问题 |
---|---|
Read Uncommitted | 数据回滚时产生脏读 |
Read Committed | 数据UPDATE时产生不可重复读 |
Repeatable Read(读数据时不允许修改) | INSERT操作产生幻读 |
Serializable | 事务串行化顺序执行,效率低下 |
回滚规则
默认事务遇到运行期异常才会回滚,而遇到检查型异常时不会回滚
- Checked Exception
所有不是RuntimeException派生的Exception都是检查型异常 - Unchecked Exception
不遵循处理或声明规则,在产生此类异常时,编译器不会检查是否已解决了这样的异常(RuntimeException和Error)
在嘲讽中成长的实习僧啊…