事务未生效可能造成严重的数据不一致性问题,因而保证事务生效至关重要。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事务不生效问题的更多相关文章

  1. Spring基础系列-Spring事务不生效的问题与循环依赖问题

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9476550.html 一.提出问题 不知道你是否遇到过这样的情况,在ssm框架中开发we ...

  2. mysql测试spring事务是否生效

    同时对三张表进行插入操作,事务保证完整性.下面进行简单测试: 1. 锁定表 锁定用户表 LOCK TABLES user WRITE; 查看表是否锁定: show ; 显示被锁定的表. 2. 验证在同 ...

  3. [转]Spring事务嵌套引发的血案---Transaction rolled back because it has been marked as rollback-only

    原文地址:https://blog.csdn.net/f641385712/article/details/80445912 1.概述 想必大家一想到事务,就想到ACID,或者也会想到CAP.但笔者今 ...

  4. spring中注解式事务不生效的问题

    常用的解决方法可以百度,我针对我的问题描述一下 Mysql中InnoDB引擎才支持事务, MyISAM不支持事务. 当你尝试了各种方法解决spring中注解式事务不生效时, 一定要查看一下数据库中表的 ...

  5. 分析spring事务@Transactional注解在同一个类中的方法之间调用不生效的原因及解决方案

    问题: 在Spring管理的项目中,方法A使用了Transactional注解,试图实现事务性.但当同一个class中的方法B调用方法A时,会发现方法A中的异常不再导致回滚,也即事务失效了. 当这个方 ...

  6. Spring中同一个service中方法相互调用事务不生效问题解决方案

    问题描述: 我们在用Spring框架开发Web项目过程中,经常需要用同一个service中的一个方法调用另一个方法,如果此时调用方没有添加事务注解@Transactional,而在被调用方添加事务注解 ...

  7. 两个与spring事务相关的问题

    有些spring相关的知识点之前一直没有仔细研究:比如spring的事务,并不是没有使用,也曾经简单的在某些需要事务处理的方法上通过增加事务注解来实现事务功能,仅仅是跟随使用(甚至并未测试过事务的正确 ...

  8. 【转】Spring事务管理

    原文链接 在 Spring 中,事务是通过 TransactionDefinition 接口来定义的.该接口包含与事务属性有关的方法.具体如清单 1 所示: 清单 1. TransactionDefi ...

  9. Spring事务讲解示例

    Spring 事务Transaction1.事务的属性1.1 事务隔离IsolationLevel1.2 事务传播PropagationBehavior1.3 事务超时Timeout1.4 只读状态R ...

随机推荐

  1. node 在centos 6.5 上 安装过程中出现/usr/lib64/libstdc++.so.6: version 'GLIBCXX_3.4.19' not found问题的解决

    node  在centos 6.5 上 安装过程中出现/usr/lib64/libstdc++.so.6: version 'GLIBCXX_3.4.19' not found问题的解决 在linux ...

  2. Java面向对象系列(7)- 什么是继承

    继承 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模 extands的意思是"扩展".子类是父类的扩展 JAVA中类只有单继承,没有多继承 继承是类和类之间的一种关系. ...

  3. Java基础系列(41)- 冒泡排序

    冒泡排序 冒泡排序无疑是最为出名的排序算法之一,总共有八大排序 冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人尽皆知 我们看到的嵌套循环,应该立马就可以得出这个算法的时间复 ...

  4. Linux C语言 取得MTU (最大传输单元)

    参照这篇博客: http://www.geekpage.jp/programming/linux-network/book/04/4-21.php * 查看主机当前网卡,哪块在使用. ifconfig ...

  5. WireShark新手使用教程

    Wireshark是非常流行的网络封包分析软件,可以截取各种网络数据包,并显示数据包详细信息.常用于开发测试过程各种问题定位.本文主要内容包括: 1.Wireshark软件下载和安装以及Wiresha ...

  6. 定要过python二级 第一套

    1.和强类型语言相对应的是弱类型语言,Python.JavaScript.PHP 等脚本语言一般都是弱类型的.弱类型语言有两个特点: 变量无须声明就可以直接赋值,对一个不存在的变量赋值就相当于定义了一 ...

  7. 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分配方式  | 百篇博客分析OpenHarmony源码 | v11.02

    百篇博客系列篇.本篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分配方式 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些 ...

  8. 2021“MINIEYE杯”中国大学生算法设计超级联赛(7)部分题解

    前言 找大佬嫖到个号来划水打比赛了,有的题没写或者不是我写的就不放了. 目前只有:1004,1005,1007,1008,1011 正题 题目链接:https://acm.hdu.edu.cn/con ...

  9. 1.pytest初尝试

    语法规范 pytest命令会默认执行以 -- test_**.py -- 或 -- **_test.py -- 命名文件的测试用例 pytest的测试用例必须以 -- test -- 开头 def t ...

  10. Unity——资源文件夹介绍

    Unity资源文件夹介绍 1.编辑时 在Asset文件下存在Resources和SteamingAsset文件夹: Resources 只读不可修改,打包时直接写死,没有办法通过热更新替换资源: 可以 ...