Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从源码级别定位事务失效

从源码级别定位事务失效

原创
作者头像
啵啵肠
发布于 2023-11-28 07:37:27
发布于 2023-11-28 07:37:27
1760
举报

1、从源码级别定位事务失效

我们知道,Spring 是通过 Spring AOP 来达到事务的回滚操作的,而 Spring AOP 又是通过动态代理实现的,这时候我们知道了事务有效的几个条件,第一是有可以执行的增强器链,也就是类似于我们平时用的各种通知,在 Spring 事务中定义了一个默认的增强器 TransactionInterceptor ,这个类在 @EnableTransactionManagement 注解中的 ProxyTransactionManagementConfiguration 被注册。第二是类能被动态代理。下面我们定位到具体的类中来分析问题。

1.1、事务类不能被代理

事务类是否能被创建代理,关键在于 AbstractAutoProxyCreator 类的 postProcessAfterInitialization 方法:

代码语言:less
AI代码解释
复制
@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;
	}

如果 Bean 没有走到这里说明当前 Bean 不能被动态代理,通常控制台会打印一条语句 is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)。这条信息由 PostProcessorRegistrationDelegate 下的 BeanPostProcessorChecker 的 postProcessAfterInitialization 打印出来的,为什么会打印这个呢?里面的注释已经明确说明了:

代码语言:c#
AI代码解释
复制
BeanPostProcessor that logs an info message when a bean is created during
 BeanPostProcessor instantiation, i.e. when a bean is not eligible for
getting processed by all BeanPostProcessors.

大概的意思就是 Bean 在 BeanPostProcessor 初始化的时候被提前初始化了,因为这个是用来处理一些普通 bean 添加一些信息的,Bean 都先于它加载了,那么自然也就处理不到它了,最常见的地方就是 Shiro 配置中提前引用了普通 Bean 导致后续不能被代理,进而导致事务失效。

1.2、类没有符合条件的增强器

我们定位到事务的增强器中,TransactionInterceptor 的 invoke 方法,然后到具体的处理细节 TransactionAspectSupport 的 invokeWithinTransaction 方法中,由这个方法去执行事务的回滚,如果 debug 到这里发现方法没有执行到这,那么事务也是失效的,最常见的就是在方法上没有添加事务注解,自然的当前类就不符合事务通知的拦截点了,增强器也就不会执行。

下面列举几种常见的事务失效原因:

2、Spring 事务失效原因

2.1、未加 Transactional 注解
2.2、方法类未被加入到 IOC 容器中

整个事务环境都是依赖于 IOC 容器的,类不在咋处理。

2.3、方法产生的异常不是 RuntimeException

我们将目光定位到以下代理,TransactionAspectSupport 的 completeTransactionAfterThrowing 方法

代码语言:scss
AI代码解释
复制
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
				try {
					txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
				}
}

DefaultTransactionAttribute 的 rollbackOn 方法:

代码语言:typescript
AI代码解释
复制
public boolean rollbackOn(Throwable ex) {
		return (ex instanceof RuntimeException || ex instanceof Error);
	}
2.4、类被提前初始化

如果控制台打印了 is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 那么要注意这个 Bean 了,因为它不能被动态代理了,处理办法就是将这个 Bean 在一些特殊类中移出来,比如配置类。

3、Spring 传播行为的处理

具体处理在 AbstractPlatformTransactionManager 的 AbstractPlatformTransactionManager 方法处理。

4、Spring 隔离级别

我们知道 Spring 对于隔离级别都是委托底层的数据库去处理的,所以在 Spring 中的具体处理细节就是设置一下隔离级别,具体在 AbstractPlatformTransactionManager 的 getTransaction 方法的 doBegin(transaction, definition); 里面,可以找一个实现类去看一下。

代码语言:text
AI代码解释
复制
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);

5、Transactional 注解中 rollbackFor 的作用

如果在注解中配置了 rollbackFor 属性,那么在走到 txInfo.transactionAttribute.rollbackOn(ex) 这里的时候,它会进 RuleBasedTransactionAttribute 的 rollbackOn 方法:

代码语言:java
AI代码解释
复制
public boolean rollbackOn(Throwable ex) {
		if (logger.isTraceEnabled()) {
			logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
		}

		RollbackRuleAttribute winner = null;
		int deepest = Integer.MAX_VALUE;

// 如果配置了 rollbackFor 那么这里就是有回滚规则的。
		if (this.rollbackRules != null) {
			for (RollbackRuleAttribute rule : this.rollbackRules) {
// 这里通过比较异常的名称是否相等,不相等则取抛出的异常的父类与定义的匹配规则比较,同时深度也加一,直到匹配出异常名称,如果最后匹配到
//Throwable异常,那就直接返回-1了,winner也为null
				int depth = rule.getDepth(ex);
				if (depth >= 0 && depth < deepest) {
					deepest = depth;
					winner = rule;
				}
			}
		}

		if (logger.isTraceEnabled()) {
			logger.trace("Winning rollback rule is: " + winner);
		}

// 没有规则就直接调用父类的回滚了不会走下去
		// User superclass behavior (rollback on unchecked) if no rule matches.
		if (winner == null) {
			logger.trace("No relevant rollback rule found: applying default rules");
			return super.rollbackOn(ex);
		}

		return !(winner instanceof NoRollbackRuleAttribute);
	}

那我们配置成 Throwable 会怎么样?

代码语言:text
AI代码解释
复制
//我们知道这个是那运行产生的异常去与规则对比的,如果规则是 Throwable 那么会匹配成功返回正数,如果没匹配到的话就会走到-1那里。
private int getDepth(Class<?> exceptionClass, int depth) {
		if (exceptionClass.getName().contains(this.exceptionName)) {
			// Found it!
			return depth;
		}
		// If we've gone as far as we can go and haven't found it...
		if (exceptionClass == Throwable.class) {
			return -1;
		}
		return getDepth(exceptionClass.getSuperclass(), depth + 1);
	}

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring 九大事务失效场景
从源码的位置 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
啵啵肠
2023/11/17
2640
上盘硬菜,@Transaction源码深度解析 | Spring系列第48篇
大家好,今天咱们通过源码来了解一下spring中@Transaction事务的原理。
路人甲Java
2020/10/26
6850
【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource
本篇博文定位为为事务相关的其余博文的工具博文,属于Spring事务相关的基础类的打点、扫盲篇。
YourBatman
2019/09/03
1.1K0
【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource
@Transactional作用(成像原理)
2.1.1、@Import和[@ImportSelector + @ImportBeanDefinitionRegistor ]
全栈程序员站长
2022/07/29
1.1K0
Spring事务管理---上
PlatformTransactionManager接口定义了事务界定的基本操作,我们可以直接使用它来进行编程式事务管理。
大忽悠爱学习
2022/06/12
7120
Spring事务管理---上
Spring事务源码解析
2.1.4. TransactionManagementConfigurationSelector
爱撒谎的男孩
2019/12/31
1.3K0
三问Spring事务:解决什么问题?如何解决?存在什么问题?
让我们先从事务说起,“什么是事务?我们为什么需要事务?”。事务是一组无法被分割的操作,要么所有操作全部成功,要么全部失败。我们在开发中需要通过事务将一些操作组成一个单元,来保证程序逻辑上的正确性,例如全部插入成功,或者回滚,一条都不插入。作为程序员的我们,对于事务管理,所需要做的便是进行事务的界定,即通过类似begin transaction和end transaction的操作来界定事务的开始和结束。
草捏子
2020/08/10
1K0
三问Spring事务:解决什么问题?如何解决?存在什么问题?
深入理解 Spring 之 SpringBoot 事务原理
我们之前的数十篇文章分析了 Spring 和 Mybatis 的原理,基本上从源码层面都了解了他们的基本原理,那么。在我们日常使用这些框架的时候,还有哪些疑问呢?就楼主而言,楼主已经明白了 IOC ,AOP 的原理,也明白了 Mybatis 的原理,也明白了 Spring 和 Mybatis 是如何整合的。但是,我们漏掉了 JavaEE 中一个非常重要的特性:事务。事务是 Java 程序员开发程序时不可避免的问题。我们就不讨论 ACID 的事务特性,楼主这里假定大家都已经了了解了事务的原理。如果还不了解,可以先去谷歌看看。那么,我们今天的任务是剖析源码,看看Spring 是怎么运行事务的,并且是基于当前最流行的SpringBoot。还有,我们之前剖析Mybatis 的时候,也知道,Mybatis 也有事务,那么,他俩融合之后,事务是交给谁的?又是怎么切换的?今天这几个问题,我们都要从源码中找到答案。
全栈程序员站长
2022/06/30
6560
深入理解 Spring 之 SpringBoot 事务原理
掌握 @transactional 注解@Transactional 注解管理事务的实现步骤Spring 的注解方式的事务实现机制
Spring 事务管理两种方式 编程式事务 通过编码方式实现事务 声明式事务 基于 AOP,将具体业务逻辑与事务处理解耦,声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多 声明式事务有两种方式 在配置文件(xml)中做相关的事务规则声明 基于@Transactional 注解的方式 注释配置是目前流行的使用方式,因此本文将着重介绍基于@Transactional 注解的事务管理 @Transactional 注解管理事务的实现步骤 第一步,在配置文件中添加事务配置信息 除了用
JavaEdge
2018/05/16
9280
Spring事务的回滚和提交你真的明白了吗,本篇文章带你走近源码。干货满满
上一篇文章讲解了获取事务,并通过获取的connection设置只读,隔离级别等;这篇文章讲事务剩下的回滚和提交。
@派大星
2023/06/28
1.4K0
Spring事务的回滚和提交你真的明白了吗,本篇文章带你走近源码。干货满满
面试前看了这篇spring事务的文章,让我多要了2k的工资
继上一篇《spring事务的这10种坑,你稍不注意可能就会踩中!!!》之后,我打算对spring的事务做详细分析,带大家一起探讨一下spring事务的设计原理和底层实现,希望这篇文章能够让你有所收获。
苏三说技术
2020/10/15
7720
面试前看了这篇spring事务的文章,让我多要了2k的工资
Spring事务AOP实现原理
此篇文章需要有SpringAOP基础,知道AOP底层原理可以更好的理解Spring的事务处理。
用户4283147
2022/10/08
5530
Spring事务AOP实现原理
spring事务源码解析
  在spring jdbcTemplate 事务,各种诡异,包你醍醐灌顶!最后遗留了一个问题:spring是怎么样保证事务一致性的? 当然,spring事务内容挺多的,如果都要讲的话要花很长时间,而本片博客的主旨是解决上一篇博客遗留的问题,那么我们把问题细化下来, 就是spring如何保证一个事务中的jdbc connection是同一个?
青石路
2018/09/10
1K0
spring事务源码解析
Spring AOP事务01
XML中的tx:annotation-driven 注解用于开启事务,在TxNameSpaceHandler 中,进行自注册增强,springboot 是通过 @EnableTransactionManagement进行注册和解析
用户3293499
2024/09/01
1780
Spring事务原理详解
spring事务开启和使用比较简单,需要有数据源和事务管理器,然后在启动门面类上开启事务,在需要使用事务的地方添加注解就可以了,我们简单做一下回顾。
叔牙
2022/01/04
7273
Spring事务原理详解
(七)Spring源码解析:Spring事务
对于事务来说,是我们平时在基于业务逻辑编码过程中不可或缺的一部分,它对于保证业务及数据逻辑原子性立下了汗马功劳。那么,我们基于Spring的声明式事务,可以方便我们对事务逻辑代码进行编写,那么在开篇的第一部分,我们就来用一个示例,来演示一下Spring事务的编写方式。
爪哇缪斯
2023/09/06
2820
(七)Spring源码解析:Spring事务
Spring事务的那些坑,这里都给你总结好了!
Spring框架已是JAVA项目的标配,其中Spring事务管理也是最常用的一个功能,但如果不了解其实现原理,使用姿势不对,一不小心就可能掉坑里。
程序员白楠楠
2020/11/22
1.6K0
【Spring源码】Spring事务原理
事务是访问并可能更新数据库中各种数据项的一个程序执行单元,这个操作单元要么全部执行成功,要么全部执行失败。同时也是恢复和并发控制的基本单位。
有一只柴犬
2024/01/25
2470
【Spring源码】Spring事务原理
Spring源码:事务管理流程分析
事务Transaction,它是一系列严密操作动作,要么都操作完成,要么都回滚撤销。
后台技术汇
2024/10/15
2220
Spring源码:事务管理流程分析
Spring事务是怎么通过AOP实现的
阅读此文章需要掌握一定的AOP源码基础知识,可以更好的去理解事务,我在另外一篇文章有提过。
@派大星
2023/07/15
3580
Spring事务是怎么通过AOP实现的
相关推荐
Spring 九大事务失效场景
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档