事务特性、事务隔离级别、spring事务传播特性

事务分为编程式事务 与 声明式事务 这里描述常用的声明式事务的原理。

@Transactional 实现机制:

  当在方法上使用@Transactional 时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常决定提交或回滚事务。


@Transactional 中相关参数说

name        :当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。

propagation   :事务的传播行为,默认值为 REQUIRED。

isolation      :事务的隔离度,默认值采用 DEFAULT。

timeout             :事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。

read-only    :指定事务是否为只读事务,默认false 为了忽略那些不需要事务的方法,如读取数据可以设置read-only为true。

rollback-for      :用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。

no-rollback- for:抛出 no-rollback-for 指定的异常类型,不回滚事务。

(重点说明)propagation : 事务的传播行为 

Propagation.REQUIRED(默认):如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。

Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。

Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。

Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。

Propagation.NESTED: Propagation.REQUIRED 效果一样。

/*
*测试用例:
*/1:默认事务 (propagation.REQUIRED)
class B{
  @Transactional
  public void funB(){ }
}
cladd A {
  @Transactional
   public void funA(){ new B().funB(); }
}

//结果为:当B失败,则funA/B同时回滚
 
//例2:(Propagation.REQUIRES_NEW) 创建新事物
//需求:funA如果抛异常不得影响funB的执行,使用新启事务 Propagation.REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void funA(){ funB} //直接失效
//这里有个坑!funB必须写在另一个类中才生效! 在默认的代理模式下,只有目标方法由外部调用,才能被 Spring 的事务拦截器拦截。
//在同一个类中的两个方法直接调用,是不会被 Spring 的事务拦截器拦截,可以使用 AspectJ 取代 Spring AOP 代理来解决这个问题。
 
//例3:(Propagation.MANDATORY) 事务有则加入无则报错
class B{
  @Transactional(propagation = Propagation.MANDATORY)
  public void funB(){ }
}
cladd A {
  public void funA(){ new B().funB(); }
}

//结果:将报错因为在调用funB的时候不存在事务。
 
//例4:(Propagation.SUPPORTS)事务有则加入,无则按非事务运行。  与例三相对
class B{
  @Transactional(propagation = Propagation.SUPPORTS)
  public void funB(){ }
}
cladd A {
  public void funA(){ new B().funB(); }
}

//例5:Propagation.NOT_SUPPORTED 与 Propagation.NEVER 都是以非事务方式执行,
//后者更狠只要有事务就报错,而前者只是暂停。

 


 

不会执行事务的场景:懂原理才能知道为什么不执行!!

为什么不启用事务的排查逻辑:

1、public:SpringAOP中涉及的核心类CglibAopProxy 或者 JdkDynamicAopProxy 无法获取@Transactional 的相关配置,底层使用反射读取配置信息,但该方法非Public 所以获取不到。

2、try/catch:核心类找到了你@Transactional 的配置,但你在方法里catch 掉了,所以事务拦截器拦截的时候抓不到异常导致无法回滚

3、同类中自调用:找到了,也没有catch.但还是没有回滚,看看是不是在同一个类中形成了自调用(同类中方法事务A调用事务方法B)这里可以参考IBM的这个博客

4、propagation:找到没也没catch也无自调用,检查Propagation 参数是否配置了不启用事务的参数

5、回滚异常检测:检查rollbackFor 以及 noRollbackFor 这里检查的异常是否有问题。

 


 

参考文章:

https://blog.csdn.net/nextyu/article/details/78669997  《Spring Boot 中使用 @Transactional 注解配置事务管理》

https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html 《透彻的掌握 Spring 中@transactional 的使用》

https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations

《Spring框架参考文档》

posted @ 2019-05-24 17:43  蓝色丶格调  阅读(156)  评论(0编辑  收藏  举报