你必须懂!也可以懂的@Transactional原理!

美团一面:@Transactional 原理和常见的坑? Java后端面试的时候,面试官经常会问到@Transactional的原理,以及容易踩的坑,今天就带大家把这几块知识吃透。这篇文章, 阅读详情

1.前言

系统应用开发过程中通常需要使用事务来保证业务数据的一致性,实现方式如:开启事务、执行数据库写操作、提交或者回滚事务,这种标准实现方式适用于少量一致性业务,如果存在大量需要保证数据一致性的业务,不仅会让开发人员重复编码,还会给系统造成冗余代码。基于这些问题,伟大的Spring框架为我们提供了@Transactional注解,那么它是如何使用一个注解就解决了我们的烦恼呢?我们该如何着手进行分析呢?
SpringBoot集成的功能往往要从一个xxxAutoConfiguration开始说起

2.自动配置

打开TransactionAutoConfiguration自动配置类可以看到一个比较重要的注解@EnableTransactionManagement用于开启事务管理功能,@EnableTransactionManagement注解又导入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration

2.1 事务配置

ProxyTransactionManagementConfiguration中声明了一个切面BeanFactoryTransactionAttributeSourceAdvisor,看到切面必定会有相对应的切点TransactionAttributeSourcePointcut(用于声明切入的范围)和通知TransactionInterceptor(用于实现切入目标的后续操作)。

2.2 声明@Transactional注解处理器

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
}

AnnotationTransactionAttributeSource实例化指定了注解解析器为SpringTransactionAnnotationParser
在这里插入图片描述
可以看到该解析器主要用来处理@Transactional注解

2.3 注入自动代理注册器

在2.自动配置提到@EnableTransactionManagement还引入了AutoProxyRegistrar,向IOC容器中注入InfrastructureAdvisorAutoProxyCreator

@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
   return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

InfrastructureAdvisorAutoProxyCreator实现了BeanPostProcessor接口,具有拦截并处理Bean的能力

2.3.1 Bean后置处理

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

2.3.2 从容器中获取所有的Advisor

/**
  * Find all candidate Advisors to use in auto-proxying.
  * @return the List of candidate Advisors
  */
protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

2.3.3 筛选出符合条件的Advisor

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    // 1.获取切点对应的MethodMatcher
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    for (Class<?> clazz : classes) {
        // 2.获取当前类中的所有方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            // 3.判断是否符合切点要求,此处的methodMatcher为TransactionAttributeSourcePointcut
            if (methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

在这里插入图片描述

判断方法上是否有@Transactional注解,如果有则使用SpringTransactionAnnotationParser进行解析并生成TransactionAttribute

2.3.4 Advisor排序

sortAdvisors(eligibleAdvisors);

2.3.4 小结

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 1.从容器中获取所有类型为Advisor的切面
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 2.筛选出符合条件的切面(也就是类或方法上被@Transactional注解标注)
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        // 3.对符合条件的切面进行升序排序
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

2.4 选择代理方法

@Override

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (!IN_NATIVE_IMAGE &&
        (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
        Class<?> targetClass = config.getTargetClass();
        // 1.如果实现接口则选择jdk代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        // 2.选择cglib代理
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

2.4.1 生成代理

此处以cglib为例

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Class<?> proxySuperClass = rootClass;

        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
        }
        enhancer.setSuperclass(proxySuperClass);
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

        Callback[] callbacks = getCallbacks(rootClass);
    }
}
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // Choose an "aop" interceptor (used for AOP calls).
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
}

创建Enhancer并指定回调为DynamicAdvisedInterceptor

2.5 调用代理

执行被代理对象目标方法userService.saveUser(user);时会调用DynamicAdvisedInterceptor的intercept()方法

2.5.1 筛选满足条件的Advice

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
    Advised config, Method method, @Nullable Class<?> targetClass) {
    // 1.遍历所有满足条件的Advisor,也就是2.3.3章节返回的Advisor
    for (Advisor advisor : advisors) {
        if (advisor instanceof PointcutAdvisor) {
            // Add it conditionally.
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                // 2. 判断是否满足切点要求
                boolean match = mm.matches(method, actualClass);
                // 3.满足切点要求
                if (match) {
                    // 3. 获取切面对应的通知,也就是TransactionInterceptor
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
        }
    }
	// 4.返回满足条件的通知
    return interceptorList;
}

2.5.2 执行满足条件的Advice

@Override
@Nullable
public Object proceed() throws Throwable {
	// 1.如果没有advice可以执行,则执行目标方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }

    // 2.从advice列表中取出一个advice
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // 3.执行advice的invoke方法,也就是TransactionInterceptor的invoke
	return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

3. 事务调用

3.1 获取事务配置属性

TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

也就是@Transactional注解声明的属性

3.2 获取事务管理器

final TransactionManager tm = determineTransactionManager(txAttr);

从容器中获取DataSourceTransactionManagerAutoConfiguration自动配置类中声明的事务管理器JdbcTransactionManager

public class DataSourceTransactionManagerAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(TransactionManager.class)
    JdbcTransactionManager transactionManager(DataSource dataSource,
                                              ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
        JdbcTransactionManager transactionManager = new JdbcTransactionManager(dataSource);
        transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
        return transactionManager;
    }
}

3.3 执行事务

在这里插入图片描述

4. 总结

@Transactional实现原理三要素切面、切点、通知

  • InfrastructureAdvisorAutoProxyCreator后置处理器拦截所有Bean
  • 遍历所有类型为Advisor的切面
  • 返回满足切点条件的切面列表
  • 选择代理方法
  • 生成代理
  • 调用通知的invoke()方法
    开启事务
    调用其它通知的invoke()方法,如果没有执行目标方法
    执行异常,回滚事务
    执行成功,提交事务
  • 执行目标方法

了解@Transactional注解实现原理,不仅可以让我们对切面、切点、通知有一个清晰的认识,还可以让我们通过其思想实现类似功能,如@Cache注解实现应用缓存,@Async注解实现业务异步执行

Java高级架构面试知识点整理

我整理的《最全Java高级架构面试知识点整理》已升级为2.0版本,200个知识点,178页。私信我“Java”获取。

Springboot之@Transactional事务注解原理详解 文章目录注册事务切面逻辑根据切面逻辑生成代理类总结 @Transactional注解的逻辑是通过动态代理来实现的,而生成这个动态代理类分成了两步: 1、向spring容器注册事务相关的切面逻辑 2、根据切面逻辑生成动态代理 下面围绕这两点来看下Springboot里的实现原理 注册事务切面逻辑 切面逻辑里有三个概念: Pointcut:负责告诉spring容器哪个类需要增强 Advise:具体的切面逻辑,这里就是根据异常进行commit或者回滚的相关逻辑 Advisor:封装了Advise和Pointcut 阅读详情

相关推荐

Spring——@Transactional事务注解原理及失效场景

Spring中的事务注解你真的用对了吗?其中的原理、传播机制、失效场景你都理解了吗

共勉 2823

spring源码阅读--@Transactional实现原理

@Transactional注解简介 @Transactional是spring中声明式事务管理的注解配置方式,相信这个注解的作用大家都很清楚。@Transactional注解可以帮助我们把事务开启、提交或者回滚的操作,通过aop的方式进行管理。通过@Transactional注解就能让spring为我们管理事务,免去了重复的事务管理逻辑,减少对业务代码的侵入,使我们开发人员能够专注于业务层面开发...

嘎嘎的博客 6万+

Spring @Transactional注解原理深度分析

Transactional注解是Spring事务管理的核心注解,定义在spring-tx@Inherited// 事务管理器限定符// 事务标签// 事务传播行为// 事务隔离级别// 事务超时时间// 只读事务标识// 回滚异常类型Class<?// 不回滚异常类型Class<?/*** 根据事务定义获取事务状态*//*** 提交事务*//*** 回滚事务*/@Component。

ma451152002的专栏 389

Spring--@Transactional解析

Transactional是Spring框架中基于 AOP 的一个注解,用于在方法级别控制事务。这个注解告诉Spring框架在方法执行过程中,使用事务管理功能。如果该方法正常执行,则事务将被提交;如果方法抛出异常,则事务将被回滚。

qq_33807380的博客 6319

Spring @Transactional工作原理详解

主要介绍了Spring @Transactional工作原理详解,具有一定借鉴价值,需要的朋友可以参考下。

SRS(简单实时视频服务) 笔记(5)- 视频录制

在SRS使用中实现视频录制功能。

irainsa的博客 1698

@Transactional失效的场景及原理

1.@Transaction修饰的方法为非public方法,这个时候@Transaction会实现。 失败的原理是:@Transaction是基于动态代理来实现的,非public的方法,他@Transaction的动态代理对象信息为空,所以不能回滚。 2.在类内部没有添加@Transaction的方法,调用了@Transaction方法时,当你调用是,他也不会回滚 测试代码如下 @Service ...

sinat_30594513的博客 1万+

FMT(基于rtthread)开源代码编译 win10下编译环境搭建及编译

FMT(基于rtthread)开源代码编译 win10下编译环境搭建及编译 什么是Firmament? Firmament (FMT) 是一款基于模型设计 (Model-Based-Design, MBD) 的开源自驾仪,可被用来快速构建无人机,无人车,无人船,机器人等平台的控制系统。 系统主要由两部分构成. FMT-Firmware: 一个基于C/C++开发的稳定、高性能的嵌入式系统. FMT-Model: 一个基于MATLAB/Simulink开发的仿真框架以及算法库. 昨天得知FMT开源飞控项目已经开

weixin_45786595的博客 2869

spring的@Transactional事务原理理解

‌REQUIRES_NEW‌:总是创建一个新的事务,如果当前存在事务,则将当前事务挂起,新的事务结束后,再恢复之前被挂起的事务。‌NOT_SUPPORTED‌:不使用事务,如果当前存在事务,则将其挂起,直到该方法完成后再继续执行。‌MANDATORY‌:必须在一个已存在的事务中执行,如果当前没有事务则抛出异常。‌NESTED‌:如果当前存在事务,则在嵌套事务内执行;‌NEVER‌:不允许在事务中执行,如果当前存在事务,则抛出异常。可以看成如下,如果有事务,则是 有嵌套的,但是到底要不要,则可以自由决定。

master-dragon的专栏 1723

Innovus实战:5分钟搞定postRoute阶段冗余hold buffer的自动清理(附PHC识别技巧)

本文分享了在数字IC后端设计中使用Innovus工具,于postRoute阶段自动清理冗余hold buffer的实战技巧。通过配置时序感知的面积回收模式,可在5分钟内安全移除非关键路径上的PHC缓冲器,有效优化芯片面积与功耗,并附有PHC识别与验证方法。

moon9的博客 399

Chapter 19 Digital Phase-Locked Loops

数字锁相环 Digital Phase-Locked Loops, 就是根据原来时钟信号, 产生新的时钟信号, which is locked or synchronized. (align 参考时钟边沿 or 在中间)

2304_76736886的博客 972

@Transactional的底层实现原理

项目内容实现方式基于 AOP + 动态代理回滚机制判断异常类型是否匹配默认行为只对和Error回滚关键类建议用法总是加上注意事项避免自调用、避免捕获异常、方法必须 public。

Java的专栏 1269

BERTopic安装指南:hdbscan依赖问题全解析(附解决方案)

本文详细解析了安装BERTopic时常见的hdbscan依赖报错问题,深入剖析了C++编译环境缺失、Python版本兼容性以及包管理渠道混用三大核心原因。针对Windows、macOS和Linux不同系统,提供了创建虚拟环境、使用conda安装预编译包、安装C++编译工具等具体解决方案,帮助用户顺利安装BERTopic并开始文本主题建模实践。

weixin_29061041的博客 212

spring @Transactional实现的原理

一个没有加@Transactional注解的方法,去调用一个加了@Transactional的方法,会不会产生事务? 文字苍白,还是用代码说话。 先写一个@Transactional的方法(本文的所有代码,可到Github上下载): @Transactional public void deleteAllAndAddOneTransactional(Customer customer) {...

yangquanwa的专栏 4659

EMC(6)——电磁场的屏蔽

假如,机箱没有开口缝隙,比如篮球这种壳体,屏蔽效能都能达到100dB,100dB,基本上把电磁场强度能衰减万倍的关系,所以,这种方式屏蔽效能非常高。一般,钣金机箱,缝隙很大,大家目视就可以看到,铝铣的机箱,比较平整,但实际情况,表面其实也是坑坑洼洼,只是,大家肉眼看不出来而已!这种安装方式,是直接在缝隙增加导电材料,存在一个问题,就是,手法温柔点,压缩度会不够,手法粗暴点,过度压缩。所以,不是说,用金属机箱就能起到屏蔽效果,重要的是,要做好机箱孔缝电磁兼容设计,否则,是金属机箱,也是摆设。

qq_39825125的博客 2179

【YOLOv8全方位学习手册】第四章 数据增强:从扩充数据到塑造模型的认知边界

"""使用 Albumentations 做自定义增强,兼容 YOLO 格式"""])# 转成 numpy# boxes 必须是 [[x_min,y_min,x_max,y_max], ...]# 在数据加载时调用你可以把集成到 PyTorch 的 Dataset 类里,或使用 Ultralytics 自带的DataLoader。

VectorShift的博客 211

@Transactional原理分析

Spring事务管理的核心原理是基于动态代理和AOP拦截实现的。当使用@Transactional注解时,Spring会在Bean初始化阶段创建代理对象(JDK或CGLIB),并在方法调用时通过TransactionInterceptor进行事务控制。事务管理器控制事务的开启、提交/回滚,并通过ThreadLocal实现资源同步。常见失效场景包括:私有方法调用、自调用、异常处理不当等。该机制通过AOP实现,对业务代码低侵入,使开发者能专注业务逻辑开发。

cxbtdd的博客 816

YOLOv8独家原创改进:原创自研 | 创新自研CPMS注意力,多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM

自研CPMS,多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 3794

手撕@Transactional实现原理!Spring-tx源码全面解析!

写到这里,终于把@Transactional从头到尾扒了个遍。从一个简单的注解开始,到代理对象的创建,再到事务的开启、提交、回滚,整个过程涉及了Spring框架的多个核心机制。不得不说,Spring的设计着实精妙,叹为观止。当然,这篇文章主要是从源码角度来分析,可能有些地方讲得不够深入,有些地方理解得也不够准确。毕竟Spring的源码博大精深,我这点水平也只是管中窥豹。如果文章中有什么错误或者遗漏的地方,欢迎大家在评论区指正,我会及时修正。

z1ztai的博客 658

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

史上最全的spring里面之@Transactional原理解析

事务拦截器: 在Spring的AOP体系中,会有一个针对@Transactional注解的拦截器,在执行被注解的方法前开启一个新的数据库事务(如果当前没有事务的话),并在方法执行后根据方法的执行情况决定是否提交或回滚事务。事务开启与提交:当方法执行时,如果该方法被@Transactional注解,则Spring会自动开启一个数据库事务,并在方法正常完成(没有抛出未捕获异常)的情况下提交事务。如果当前没有事务,则创建一个新的事务。REQUIRES_NEW:总是新建一个事务,如果当前存在事务,则挂起当前事务。

qq_31532979的贺公子之数据科学与艺术博客,致力于科技向善,拥抱开源,要用技术的影响力来领导团队,而不是威权和职位! 2914

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

SpringBoot下@Transactional原理

一、@Transactional的使用 加在方法上:方法内的所有操作处于一个事务中 加在类上 该类的所有public修饰的方法都具有共享事务属性 如果方法和类上都有事务注解,方法上的事务注解优先 二、@Transactional原理 Springboot目前最为流行,它的约定大于配置的特性深受大家喜欢,注解驱动开发已成为主流。面向元数据遍历已经成为越来越多开发者的偏好,因此原理从Springboot的EnableTransactionManagement注解说起 1、@EnableTransact

weixin_41951205的博客 2708

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

@transactional注解原理_Spring 的事务实现原理和传播机制

本节思维导图事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式两种。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体的逻辑与事务处理解耦。生命式事务管理使业务代码逻辑不受污染,因此实际使用中声明式事务用的比较多。声明式事务有两种方式,一种是在配置文件(XML)中做相关的事务规则声明,另一种是基于 @T...

weixin_39845113的博客 5233

Mysql--实战篇--@Transactional失效场景及避免策略(@Transactional实现原理,失效场景,内部调用问题等)

在Spring框架中,@Transactional注解用于声明式事务管理,能够简化事务的处理逻辑。然而,在某些情况下,@Transactional可能会失效,导致事务无法按预期工作。了解这些失效场景及其原因,可以帮助你更好地管理和调试事务问题。

weisian的博客 3万+

Spring事务@Transactional注解原理

一、思维导图 Spring 事务管理分为编程式和声明式两种。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体的逻辑与事务处理解耦。 声明式事务有两种方式,一种是在配置文件(XML)中做相关的事务规则声明,另一种是基于 @Transactional 注解的方式。 默认配置下 Spring 只会回滚运行时、未检查异常(继承自 RuntimeException 的异常)或者 Error。 @Transactional 注解只能应用到 public 方法才有效。 1.1 声明式事务管理实现

jike11231的博客 1万+

细说@Transactional用法及原理

第一天: 小白:小黑,今天发现数据库有好多脏数据,这咋回事? 小黑:(内心OS,什么玩意,都不自己查一下,直接扔个这么广泛的问题给我)呃。。。你要不去检查一下相关操作到数据库接口的逻辑?特别是插入和更新操作的 小白:嗯,有道理,我去check一下。 1个小时后…… 小白:哎,小黑啊,我把相关接口check了一遍,发现正常情况下逻辑都没什么问题呀? 小黑:(内心OS,WTF?小白这个名字真不是盖的...

_ACME_的博客 3724

@Transactional 实现原理

Spring 框架通过 AOP 机制实现了声明式事务管理,核心是通过 @Transactional 注解控制事务的开启、提交和回滚。Spring 事务模块的核心组件包括 TransactionInterceptor、PlatformTransactionManager 和 TransactionAttributeSource 等。启用事务管理需使用 @EnableTransactionManagement 注解,Spring 会注册事务拦截器和事务属性源,并通过 AOP 代理机制生成代理对象。代理对象在方法

红血哥 991
上一篇: 肝了一夜的源码,终于可以通过源码分析MyBatis的缓存了!
下一篇: 阿里Java岗二面:Redis了解?说说持久化机制及RDB/AOF应用场景分析
普通网友
博客等级 码龄5年 1974粉丝 9原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值