Spring AOP事务管理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Daybreak1209/article/details/80607398

前两篇写了将Spring AOP应用与入参校验和拦截方法进行日志打印。本篇继续应用三AOP应用于事务管理,顺便把事务相关技术点统一Review一遍。(同样基于case)

一、事务管理回顾

基于用户支付成功后,创建支付订单和支付记录(两个表的insert操作)来回顾事务管理。一共涉及3个方法

1)创建pay支付记录逻辑 2)创建order支付订单逻辑 3)组合方法:调用方法1、2,同步创建支付记录和支付订单

下表case默认(表1)

1、保证事务的均采用Required传播属性。

2、执行方法2先,1后,因为都在1中写的业务异常测试 

 

组合

Method1

Method2

执行结果

是否有事务

throw

12均成功,后抛出异常

 

throw

(业务异常)

2成功,1失败

 

throw

(业务异常)

12均失败

 

throw

12均失败

1)分析:pay方法执行便立即提交commit,order同理。即便最后抛出异常,结果照样正常入库。

2)分析:同上,pay方法执行insert后立即执行commit请求,支付记录入库。而创建订单逻辑报错,创建失败。

3)分析:尽管pay、order分别存在两个事务,但当组合方法增加事务管理时,在执行pay事务后,并未执行commit请求,而是等着order执行成功后,一并commit。所以在order逻辑报错后,事务回滚,表现就是pay和order均未创建。

4)分析:虽然12逻辑正常,组合方法最后设置抛出异常操作,故组合方法commit不执行,直接rollback

结论

1、当组合方法不添加事务管理时,无论单个方法是否包含事务,也无论报错是原于单个方法中逻辑问题错误,还是两个事务逻辑正常手动抛exeption的异常,背后都是先执行逻辑没问题即刻提交commit,先执行先成功。组合方法无原子性。

2、当组合方法添加事务管理时,无论何种异常,都校验到事务中所有操作均成功后,再提价组合事务commit操作,期间有一个失败,则两单个事务都入库失败。事务性无关单个方法事务,由组合方法事务保证原子性。

注意:

在case3时犯了一个很低级的错误,创建order内部异常时,由于代码主动catch了异常,虽然是三个方法都设置了required事务,但由于catch了第一个方法异常,第二个方法仍会顺序执行,最后一起commit组合方法的提交。所以表象看起来好像外层保证了原子性,但结果确实一张表失败,一张表insert成功。

所以虽然是配置事务传播属性,但还跟代码具体写法相关。尤其是错误处理是否throw出来异常,还是catch住接下来的逻辑正常执行。这个得配合具体业务场景设计。

二、Spring事务传播属性

以下所有表格case默认:有事务表示case中均采用要验证的传播属性,例如本case验证Required,有则表示都设置成的传播Required。非默认传播属性会特别标明。(表2)

1、Required 

 

组合

Method1

Method2

执行结果

是否有事务

无throw

12均成功

 

无throw

有(异常)

1成功,2失败

 

有throw

无(异常)

12均失败

 

有throw

有(异常)

12均失败

1)1、2required加入到无事务中,自启事务保证commit操作

2)由于组合方法无事务,当2事务异常,1仍执行成功,表明required所起的新事务,仅保证自身方法原子性。而不保证整个组合方法原子性(否则因为2异常失败,1也该失败)。注意外部无事务保证。

3)组合方法有事务保证,被调起的12无事务,因2的异常,导致组合方法整个事务回滚,12均失败。

4)组合有事务保证,1的required会新起事务,保证1执行成功。2由于异常,失败。但1并未回滚,验证了2)中的说法。

其实“表1”跟“表2”的case基本重合,都验证了两点。

1、当外部操作有事务时,被调起的方法若传播属性是Required,则直接加入到外部事务,即便先执行被调起方法也不会commit,而是由外部事务统一控制commit操作。即在执行被调用方法后,若外部事务执行异常,被调起的方法随外部事务一起回滚。简言之:原操作有事务,加入到原事务中,统一由原事务管理,失败一并回滚。

2、当外部方法无事务保证时,被调起required事务传播属性的事务方法,若原操作无事务,required事务方法将自启事务,但注意!!新起的事务仅保证自身即被调起方法的事务执行,成功即提交,原操作执行失败,被调起事务也不会回滚。即表2中第二行case,1成功2失败。

2、Surport

被调用为sruppot传播属性时,如果原操作有保证事务,即以事务的形式运行,如果原操作无保证事务,那么就以非事务的形式运行

 

组合

Method1

Method2

执行结果

是否有事务

无throw

无(异常)

1成功,2失败

 

有throw

无(异常)

12均失败

 

Surport throw

无(异常)

1成功,2失败

1) 组合方法无事务保证,1以sup,则直接按无事务执行,1成功,2有异常失败

2) 组合方法有事务保证(设置为Required),1以sup,此时加入到组合方法事务中执行,当2异常时,1也回滚,两个操作均失败

3) 组合方法有事务保证(设置为sup),因为程序入口为Test不保证事务,则组合方法便按无事务顺序执行,1也是sup,同理。故1成功,2异常失败。

3、MANDATORY

必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常

.

组合

Method1

Method2

执行结果

是否有事务

12均成功

结果并未抛异常! C heck

4、REQUIRES_NEW

 

组合

Method1

Method2

执行结果

是否有事务

Re

有Re_New

12均成功

 

Re

有Re_New

无(异常)

1成功,2失败

 

Re

有Re_New(异常)

1失败,2成功

 1)组合方法事务级别为REQUIRED,到1时,1会新起事务,组合方法事务挂起,等待1事务执行结果后,执行2,12均无异常,均成功。

2)此时若2异常,1在新事务中执行成功,由于2异常组合事务执行失败回滚。而由于1在全新的事务中已commit,故1不会回滚,成功执行。

3)此时如果1异常,回滚。组合中catch住1的异常后,挂起的事务继续执行2,2无异常,组合事务正常commit。

5、NESTED

NESTED与REQUIRES_NEW的区别是,REQUIRES_NEW另起一个事务,将会与他的父事务(组合方法中的事务)相互独立,而Nested的事务和它的父事务是相依的,需要等父事务一块提交的。如果父事务最后回滚,Nested也将回滚不执行commit操作。

6、NOT_SUPPORTED

被调用的方法采用该传播属性时表示我不支持事务。如遇源操作配置需保证事务处理,则原操作执行到调用方法时,事务会被挂起,等待被调用方法顺序执行完毕后,再继续执行原操作的事务。

 

组合

Method1

Method2

执行结果

是否有事务

Re

有(异常)

1异常被catch后,执行2成功

 

Re

有(异常)

无(异常)

1、2均打印异常,2由异常失败

1)组合方法已有事务保证,执行到1时,事务挂起,1中异常(使用trycatch打印日志),catch完后,2正常执行

2)当2中也发生异常时,2也失败回滚。

7、NEVER

被调用的方法不能在事务中运行。如遇源操作配置需保证事务处理,则原操作执行到调用方法时,被调用方法直接抛异常。

 

组合

Method1

Method2

执行结果

是否有事务

Re throw

12均成功

1) 在required事务里里,1也没有抛异常,不起作用(未完待续)

Spring AOP事务管理配置



猜你喜欢

转载自blog.csdn.net/Daybreak1209/article/details/80607398