ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring事务不生效问题

2021-11-02 18:00:23  阅读:119  来源: 互联网

标签:事务 调用 Spring 代理 生效 save 方法 public


事务未生效可能造成严重的数据不一致性问题,因而保证事务生效至关重要。Spring事务是通过Spring aop实现的,所以不生效的本质问题是spring aop没生效,或者说没有代理成功,所以有必要了解下spring aop。

spring事务不生效场景

  • 非public修饰方法
    • private修饰
      @Transactional
      private void save(){...}
      调用save方法,事务不生效
    • protected修饰
      @Transactional
      protected void save(){...}
      调用save方法,事务不生效
  • final修饰的public法或类
    • final修饰方法
      @Transactional
      public final void save(){...}
      调用save方法,事务不生效
    • final修饰类
      @Transactional
      public final class UserService{...}
      调用UserService的方法,事务不生效
  • 被代理对象内部方法调用
    • 非事务方法调用内部事务方法
      public void save(){
      insert()
      }
      @Transactional
      public void insert(){...}
      此时调用save()方法,insert()上的事务不生效
    • 事务方法调用内部事务方法
      @Transactional
      public void save(){
      insert()
      }
      @Transactional
      public void insert(){...}
      此时调用save()方法,insert()上的事务不生效,save()方法正常调用时(非内部方法调用)事务生效

Spring aop的简单介绍

spring aop支持动态代理(运行时代理)和静态代理(编译期织入)

  • 基本概念

    • target对象
      目标对象,即想要代理的目标。
    • proxy
      代理对象,访问目标对象的方法,需要通过代理对象,无法直接访问目标对象。
      代理对象可能允许,最终调用目标对象方法,也可能不允许。
  • 静态代理(Aspectj)
    1.该实现需要使用特殊编译器,一般不使用,spring只是提供相应的整合实现。
    2.使用动态代理已经可以完成80%以上的需求了。
    3.本文也是基于动态代理的情况下讨论事务不生效情况的。
    4.因此在此不展开详细讨论。

  • 动态代理(CGLIB&JDK)

    • JDK动态代理
      1.JDK动态代理通过实现相同接口实现代理(Proxy)
      2.spring管理的Bean中是对应的是Proxy
      3.Proxy对象中包含target对象
      4.目标方法可以执行时,总是调用target的原生方法
      5.事务aop默认publicMethodsOnly(该配置未提供直接修改-AnnotationTransactionAttributeSource)
    • CGLIB动态代理
      1.CGLIB动态代理通过继承目标类生成子类作为代理
      2.spring管理的Bean中是对应的是Proxy
      3.Proxy对象中包含target对象
      4.目标方法可以执行时,总是调用target的原生方法
      5.事务aop默认publicMethodsOnly(该配置未提供直接修改-AnnotationTransactionAttributeSource)

Spring 事务不生效情况(即aop不生效情况),原因解析

  • 无法代理
    • 方法使用非public修饰(protected、private等等)
      @Transactional
      private void save(){...}

      @Transactional
      protected void save(){...}
      spring 事务aop默认publicMethodsOnly,即只有public修饰的方法,会被代理,private和protected修饰的方法save()无法被代理,事务无效。
    • 方法使用final修饰
      @Transactional
      public final void save(){...}
      CGLIB动态代理通过生成子类的方式代理,final方法无法重写
    • 类使用final修饰
      @Transactional
      public final class UserService{...}
      CGLIB动态代理通过生成子类的方式代理,final类无法生成子类
  • 未通过proxy对象调用
    • 非事务方法调用内部事务方法
      public void save(){
      insert()
      }
      @Transactional
      public void insert(){...}
      该情况隐含使用this关键字,因此被代理对象的内部事务方法insert()直接被调用,而不经过代理对象;
      内部方法insert()上的事务无效。
    • 事务方法调用内部事务方法
      @Transactional
      public void save(){
      insert()
      }
      @Transactional
      public void insert(){...}
      该情况隐含使用this关键字,因此被代理对象的内部事务方法insert()直接被调用,而不经过代理对象;
      内部方法insert()上的事务无效,但是事务方法save()正确调用时(通过代理对象调用),save()方法的事务生效。

调试辅助

当无法通过代码分析确定是否有事务(aop是否代理成功)时,可以在开发环境调试确认

  • 事务AOP
    在配置了expose-proxy=true时,调用静态方法TransactionAspectSupport.currentTransactionStatus()可以获取当前事务信息;
    该信息存储在ThreadLocal类型的线程变量;不存在时会抛异常,所以使用时需要try-catch。
  • 其他AOP
    在配置了expose-proxy=true时,调用静态方法AopContext.currentProxy()可以获取当前代理对象;该对象存储在ThreadLocal类型的线程变量;不存在时会抛异常,所以使用时需要try-catch。

标签:事务,调用,Spring,代理,生效,save,方法,public
来源: https://www.cnblogs.com/castamere/p/15500177.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有