spring事务的配置以及事务传播机制和相关的测试demo

在实际项目中为了保证数据的一致性,事务是非常重要的,而spring对事务的支持方便了我们对事务相关操作的开发.

 

事务的配置方式


spring支持编程式事务管理和声明式事务管理两种方式。
   编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
  声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
  声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

 

 

事务传播机制

标题
名称 作用
REQUIRED
支持当前事务,如果当前没有事务,则新建事务;
如果当前存在事务,则加入当前事务,合并成一个事务

 

SUPPORTS
如果当前存在事务,则加入事务。 
如果当前不存在事务,则以非事务方式运行,这个和不写没区别
REQUIRES_NEW
新建事务,如果当前存在事务,则把当前事务挂起
这个方法会独立提交事务,不受调用者的事务影响,父级异常,它也是正常提交
NOT_SUPPORTED
该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
NEVER 该传播机制不支持外层事务,即如果外层有事务就抛出异常
MANDATORY 与NEVER相反,如果外层没有事务,则抛出异常
NESTED

如果当前存在事务,它将会成为父级事务的一个子事务,方法结束后并没有提交,只有等父事务结束才提交
如果当前没有事务,则新建事务
如果它异常,父级可以捕获它的异常而不进行回滚,正常提交(这点验证失败)
但如果父级异常,它必然回滚,这就是和 REQUIRES_NEW 的区别

 

 

 

 

 

 

 

 

 

 

 

 

相关的测试

1、REQUIRED

a、如果inserA(有事务)当inserA调用inserB(无事务)时,inserB的是否有事务?

运行结果如下:

  结果:如果inserA(有事务)当inserA调用inserB(无事务)时,他会给inserB创建一个事务,并合并成一个事务.

b、如果当inserA(无事务)调用insertB(有事务)时,那么insertB的事务会执行吗?

运行结果:

结果:如果当inserA(无事务)调用insertB(有事务)时,insertB的事务是不会执行的事务回滚的,即insertB的事务不起作用

结论:

支持当前事务,如果当前没有事务,则新建事务;
如果当前存在事务,则加入当前事务,合并成一个事务

 

 

2、SUPPORTS

1、如果当inserA(required)调用insertB(supports)时,insertB的事务会回滚吗?

执行结果:

结果:如果当inserA(required)调用insertB(supports)时,insertB的事务会回滚.

b、如果当inserA(无事务)调用insertB(supports)时,insertB的事务会回滚吗?

结果如下:

结论:如果当inserA(无事务)调用insertB(supports)时,insertB的事务不会回滚

 

c、如果当inserA(supports)调用insertB(supports)时,insertB的事务会回滚吗?

结果如下:

结果:如果当inserA(supports)调用insertB(supports)时,insertB的事务不会回滚

 

d、如果当inserA(supports)调用insertB(required)时,insertB的事务会回滚吗?

结果如下:

结果:如果当inserA(supports)调用insertB(supports)时,insertB的事务不会回滚

 

结论

如果当前存在事务,则加入事务。
如果当前不存在事务,则以非事务方式运行,这个和不写没区别

 

REQUIRES_NEW

a、如果当insertLog(无事务)调用insertLogB(事务REQUIRES_NEW)时,会怎样?

结果如下:

结果:

如果当insertLog(无事务)调用insertLogB(事务REQUIRES_NEW)时,insertLogB创建了事务,并且insertLogB回滚事务,只有user的数据插入成功.

 

b、如果当insertLog(事务REQUIRES_NEW)调用insertLogB(无事务)时,会怎样?

结果如下:

结果:如果当insertLog(事务REQUIRES_NEW)调用insertLogB(无事务)时,insertLog创建了事务,并且insertLogB也创建了事务,并合并的了事务,且因报错,而回滚数据了.

 

c、如果当insertLog(事务REQUIRES)调用insertLogB(事务REQUIRES_NEW)时,会怎样?

结果如下:

结果:如果当insertLog(事务REQUIRES)调用insertLogB(事务REQUIRES_NEW)时,insertLogB独立提交事务,不受调用者的事务影响,父级异常,它也是正常提交

 

总结

新建事务,如果当前存在事务,则把当前事务挂起

这个方法会独立提交事务,不受调用者的事务影响,父级异常,它也是正常提交

 

NOT_SUPPORTED

a、如果当insertLog(无事务)调用insertLogB(无事务NOT_SUPPORTED)时,会怎样?

结果如下:

结果:  如果当insertLog(无事务)调用insertLogB(无事务NOT_SUPPORTED)时,以非事务方式运行

 

b、如果当insertLog(事务)调用insertLogB(无事务NOT_SUPPORTED)时,会怎样?

结果如下:

结果:如果当前存在事务,则把当前事务挂起

总结

以非事务方式运行

如果当前存在事务,则把当前事务挂起

 

NEVER

a、如果当insertLog(无事务)调用insertLogB(事务NEVER)时,会怎样?

结果如下:

结果:如果当insertLog(无事务)调用insertLogB(事务NEVER)时,会正常执行,

 

b、如果当insertLog(有事务)调用insertLogB(事务NEVER)时,会怎样?

结果如下:

结果:如果当insertLog(required)调用insertLogB(事务NEVER)时,使用事务NEVER会报异常,并且会回滚数据.

总结

该传播机制不支持外层事务,即如果外层有事务就抛出异常

 

 

MANDATORY

a、如果当insertLog(有事务)调用insertLogB(事务MANDATORY)时,会怎样?

结果如下:

结果:正常执行

 

 

b、如果当insertLog(无事务)调用insertLogB(事务MANDATORY)时,会怎样?

结果如下:

结果:如果当insertLog(无事务)调用insertLogB(事务MANDATORY)时 ,会报异常

结论:

与NEVER相反,如果外层没有事务,则抛出异常

 

NESTED

  

a、如果当insertLog(无事务)调用insertLogB(事务NESTED)时,会怎样?

结果如下:

结果:如果当insertLog(无事务)调用insertLogB(事务NESTED)时,如果当前没有事务,则新建事务,并且insertLogB回滚了数据

b、如果当insertLog(有事务,有异常)调用insertLogB(事务NESTED)时,会怎样?

结果如下:

结果: 如果当insertLog(有事务)调用insertLogB(事务NESTED)时,说明数据回滚了,即自方法正常,父方法有异常的情况下,全部回滚

c、如果当insertLog(有事务)调用insertLogB(事务NESTED,有异常)时,会怎样?

 

结果如下:

结果:如果当insertLog(有事务)调用insertLogB(事务NESTED,有异常)时,数据全部回滚.

 

总结

如果当前存在事务,它将会成为父级事务的一个子事务,方法结束后并没有提交,只有等父事务结束才提交
如果当前没有事务,则新建事务
如果它异常,父级可以捕获它的异常而不进行回滚,正常提交
但如果父级异常,它必然回滚,这就是和 REQUIRES_NEW 的区别

 

测试源码在GitHub上spring-framework下mySpring项目的com.lquan.trans包下(欢迎大家多多给意见,谢谢)

 

可参考,方便记忆

https://www.cnblogs.com/libin2015/p/12556163.html

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章