spring事务的5种隔离级别、spring事务的7中传播特性的理解?

一、事务的基本原理
spring事务的本质是建立在数据库事务的基础上的。
二、spring启动的时候会去解析生成相关的bean,这时候会去查拥有注解的类和方法,并且为这些类和方法生成代理,比根据@transaction的相关参数进行相关的配置注入,这样就在代理中为我们把相关的事务处理掉了。
三、spring事务的传播属性
| 常量名称 |常量解释 |
|PROPAGATION_REQUIRED|支持当前事务,如果当前没有事务,就新建一个事务,也是spring默认的事务传播特性|
|PROPAGATION_REQUIREDS_New|新建事务,如果当前存在事务就将其挂起,新建的事务和被挂起的事务没有任何关系,是两个独立的事务|
|PROPAGATION_SUPPORTS |支持当前事务,如果当前没有事务,就以非实物的方式执行|
|PROPAGATION_MANDATORY|支持当前事务,如果当前没有事务就抛出异常|
|PROPAGATION_NOT_SUPPORTED|以非事务的形式运行,如果当前存在事务,则挂起 |
|PROPAGATION_NEVER|以非事务的形式运行,如果当前存在事务,则抛出异常 |
|PROPAGATION_NESTED||

四、数据库的隔离级别
read_uncommitted:导致脏读
read_committed:避免脏读,允许不可重复读和幻读
repeatable_read:避免脏读、不可重复读,允许幻读
serializable:串行化读,事务只能一个一个的执行,避免脏读、不可重复读、幻读。但是效率慢

脏读:A事务正在写一个数据,但是事务未提交,B事务来读取该数据,B读取完后A又回滚了数据,这时B就读取到了脏数据。

不可重复读:同一个事务中发生了两次读操作,两次读操作之间另一事务对数据进行了写操作,从而造成两次读取的数据不一致。

幻读:第一个事务对一定范围内的数据进行批量修改,第二个事务在这个范围内增加了一条数据,这时候第一个事务会丢失对新增数据的修改。

isolation_Default:这个是PlatfromTransactionManager默认的隔离级别。
isolation_read_uncommitted:导致脏读
isolation_read_committed:避免脏读,允许不可重复读和幻读
isolation_repeatable_read:避免脏读、不可重复读,允许幻读
isolation_serializable:串行化读,事务只能一个一个的执行,避免脏读、不可重复读、幻读。但是效率慢

PROPAGATION_REQUIRED(spring 默认)

如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。

假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。

这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。

PROPAGATION_REQUIRES_NEW

比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。

那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。

他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。

PROPAGATION_SUPPORTS

假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。

PROPAGATION_NESTED

现在的情况就变得比较复杂了, ServiceB.methodB() 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢?
ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:

a、捕获异常,执行异常分支逻辑

void methodA() {

    try { 

        ServiceB.methodB(); 

    } catch (SomeException) { 

        // 执行其他业务, 如 ServiceC.methodC(); 

    } 

}

这种方式也是嵌套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点。

b、 外部事务回滚/提交 代码不做任何修改, 那么如果内部事务(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), 外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback

另外三种事务传播属性基本用不到,在此不做分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值