当前位置: 首页 > ds >正文

@Transactional注解失效

@Transactional注解失效

在工作中,因为对该注解的原理了解不深导致出现bug,现进行记录。
场景复现:
在同一个类中,一个方法调用了另一个被@Transactional注解修饰的方法,此时事务是不生效的。我们进行try-catch将异常进行捕捉,信息为:java.lang.IllegalStateException: Transaction synchronization is not active。它标识事务未起效。
接下类我们来看看为什么它不生效

1.SpringAop的原理

用平时最常用的AspectJ来举例,它是使用Cglib进行反射生成代理对象进行我们的切面处理。抽象的来说,这就相当于将我们的切面操作的代码直接移植到原有的类上面去,再生成一个新的类。达到我们想要的切面效果。

2.@Transactional注解

当我们进入Transactional发现它就是一个注解,没有任何实现方法,那就说明它肯定是被框架所检测,然后在框架中去具体实现它的功能。

3.举例
public class TransactionAop {public void doWithoutTransaction() {log.info("doWithoutTransaction this: {}", this.getClass().getName());doWithTransaction();}@Transactionalpublic void doWithTransaction() {try{TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {@Overridepublic void afterCommit() {log.info("doWithTransaction this: {}", this.getClass().getName());}});}catch (Exception e) {log.info(e.getMessage());}}
}

通过VisualVm只管的看到同一个类TransactionAop生成了两个对象

在这里插入图片描述

第一点:第一个对象都是通过Cglib生成的代理对象。第二个对象是Spring初始化时通过反射创建的原始对象。在初始化对象时,会去扫描整个类,标记那些方法被增强了。
第二代:Spring在调用一个对象的方法时,会去检查拦截器链。即使一个方法没有被增强,也会走一遍这个流程,去判断拦截器链为空,不会发生AOP事件。这里Spring做了缓存,方法只有在第一次被调用时会去检查,后续直接走缓存。

在调用doWithoutTransaction()时,通过match方法,检查这个方法是否被匹配上了。
那怎么匹配的,匹配的是什么东西呢?
在类AbstractFallbackTransactionAttributeSource中存在一个ConcurrentHashMap缓存,Spring会所有扫描到的被@Transiactional修饰的方法缓存起来。——Map<Object, TransactionAttribute> attributeCache

这里的Key是下面这个对象,所以具体的关系就是方法和类绑定起来成为一个Key

public final class MethodClassKey implements Comparable<MethodClassKey> {private final Method method;@Nullableprivate final Class<?> targetClass;}

可以看到在调用doWithoutTransaction时

在这里插入图片描述

在这里插入图片描述

没有匹配上,后续在找拦截器时就没有

而调用doWithTransaction时就匹配上了,可以看到他的事务等级为开启事务
在这里插入图片描述

4.那我就是需要让同一个类中的调用生效怎么办?
 // 获取当前代理对象,并调用事务方法
TransactionAop selfProxy = (TransactionAop) AopContext.currentProxy();
selfProxy.doWithTransaction();
http://www.xdnf.cn/news/5469.html

相关文章:

  • 仿制药研发为何要上电子实验记录本?
  • 数据在内存中的存储
  • 配置高级相关
  • Open CASCADE学习|B 样条曲线拟合优化
  • 探秘 Canva AI 图像生成器:重塑设计创作新范式
  • vs python“““标记注释报错,vs使用自带环境安装 python第三方库
  • 每日一题洛谷T534125 合数c++
  • C# 方法(ref局部变量和ref返回)
  • 测试一下多模态提取图片中文字的能力
  • STM32F103单片机在不需要使用 JTAG 调试接口的情况下,释放引脚给其他功能使用。
  • 电网拓扑分析:原理与应用
  • Crewai Community Version(四)——Crew
  • Qt QCheckBox 使用
  • 【Java ee初阶】网络编程 TCP
  • 深度学习篇---姿态检测实现
  • 软考错题集
  • Java 23种设计模式 - 行为型模式11种
  • PostgreSQL 的 pg_collation_actual_version 函数
  • 【深度学习-Day 8】让数据说话:Python 可视化双雄 Matplotlib 与 Seaborn 教程
  • Kimball
  • Python 基础语法与数据类型(七) - 函数的定义与调用 (def, return)
  • Ethercat转Profinet网关如何用“协议翻译术“打通自动化产线任督二脉
  • Looper死循环阻塞为什么没有ANR
  • 【大模型面试每日一题】Day 14:大模型训练中显存占用的主要来源有哪些?如何通过激活重计算降低显存?
  • 关于char字符的16进制打印
  • 408考研逐题详解:2009年第11题
  • PySide6 GUI 学习笔记——常用类及控件使用方法(常用类边距QMargins)
  • 数字信号处理|| 快速傅里叶变换(FFT)
  • 软考(信息系统运行管理员)
  • 猿人学第十七题—天杀的http2.0