spring-transaction源码分析(3)Transactional事务失效原因
问题概述
在Transactional方法中使用this方式调用另一个Transactional方法时,拦截器无法拦截到被调用方法,严重时会使事务失效。
类似以下代码:
@Transactional
public void insertBlogList(List<Blog> blogList) {
for (Blog blog : blogList) {
this.blogMapper.insertBlog(blog);
}
try {
TimeUnit.SECONDS.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Transactional
public void deleteBlogByCondition(BlogSearchParameter parameter) {
List<Blog> blogs = this.blogMapper.selectBlogByParameter(parameter);
for (Blog blog : blogs) {
this.blogMapper.deleteBlog(blog.getId());
}
// 抛出一个RuntimeException
throw new RuntimeException("deleteBlogByCondition抛出一个异常");
}
@Transactional
public void insertAndDeleteBlogList2(List<Blog> blogList, BlogSearchParameter parameter) {
// 插入数据
this.insertBlogList(blogList);
// 删除数据
try {
this.deleteBlogByCondition(parameter);
} catch (Exception e) {
System.err.printf("Err:%s%n", e.getMessage());
}
System.out.println("继续插入数据");
// 继续插入数据
this.insertBlogList(blogList);
}
正常情况下,执行到"继续插入数据"时会抛出一个"rollback only"的异常,然后事务回滚。
而现在的现象是:
- 三个操作都不会开启事务,出现异常也不会回滚
- "删除数据"操作会把符合条件的数据都删除掉
- "继续插入数据"操作会再插入数据
原因分析
在EnableTransactionManagement注解mode属性的文档中:
The default is AdviceMode.PROXY. Please note that proxy mode allows for interception of calls through the proxy only.
Local calls within the same class cannot get intercepted that way; an Transactional annotation on such a method within
a local call will be ignored since Spring's interceptor does not even kick in for such a runtime scenario.
For a more advanced mode of interception, consider switching this to AdviceMode.ASPECTJ.
大概意思是:mode属性的默认值是AdviceMode.PROXY,这种方式仅允许通过代理对来调用事务方法,同一个类的本地调用无法被事务切面拦截。如果要解决这个问题,可以使用AdviceMode.ASPECTJ模式。
其实这个问题的根本原因与spring-tx无关,而是spring-aop的实现方式造成的。
从spring-aop拦截器分析问题原因
在DynamicAdvisedInterceptor和JdkDynamicAopProxy中有一段类似的代码:


其中target就是原始的业务层Bean对象。
在后续创建ReflectiveMethodInvocation/CglibMethodInvocation时又将此target传递了进去:
// JDK
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
// Cglib
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
proceed方法中在拦截器链最后会调用目标方法:
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 略
}
protected Object invokeJoinpoint() throws Throwable {
// 反射调用目标方法
// 这个target就是原始Bean对象
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
所以如果在目标方法中使用this方法调用另一个需要被拦截的方法,将不会执行拦截逻辑。
spring-transaction源码分析(3)Transactional事务失效原因的更多相关文章
- spring transaction源码分析--事务架构
1. 引言 事务特性 事务是并发控制的单元,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性.事 ...
- Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...
- Spring AMQP 源码分析 02 - CachingConnectionFactory
### 准备 ## 目标 了解 CachingConnectionFactory 在默认缓存模式下的工作原理 ## 前置知识 <Spring AMQP 源码分析 01 - Impatie ...
- 5.2 Spring5源码--Spring AOP源码分析二
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- 5.2 spring5源码--spring AOP源码分析二--切面的配置方式
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- Spring Security 源码分析(四):Spring Social实现微信社交登录
社交登录又称作社会化登录(Social Login),是指网站的用户可以使用腾讯QQ.人人网.开心网.新浪微博.搜狐微博.腾讯微博.淘宝.豆瓣.MSN.Google等社会化媒体账号登录该网站. 前言 ...
- spring AOP源码分析(三)
在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- Spring AOP 源码分析 - 筛选合适的通知器
1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...
随机推荐
- 【算法】Java版
二分查找算法 二分查找算法(Binary Search Algorithm)是一种在有序数组中查找特定元素的搜索算法.该算法的基本思想是将数组从中间分成两部分,然后与目标元素进行比较,进而确定目标元素 ...
- Java:字符串(String)类型转成整型(int)的方法
Java:字符串(String)类型转成整型(int)的方法 使用 Integer.parseInt() 或 Integer.valueOf() 将 String 转换为 int. 其中: Integ ...
- ElasticSearch之文件描述符的数量
ElasticSearch在运行过程中,涉及大量文件的打开.关闭.读.写等操作.因此当ElasticSearch进程的文件描述符数量不足时可能导致丢失数据等故障现象. 因此为保障ElasticSear ...
- vulnhub - Aragog - writeup
信息收集 目标开放了80.22端口. root@Lockly temp/tmp » arp-scan -I eth1 -l Interface: eth1, type: EN10MB, MAC: 00 ...
- Python——第一章:循环语句while——break和continue
while True: content = input("请输入你要发送的内容(q结束):") print("发送内容:", content) 这样的代码会无限 ...
- 一文读懂Spring框架中依赖注入流程
想读懂Spring的依赖注入流程,我们先简单了解一下Ioc和DI是什么? IoC和DI Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计 ...
- struts2 Filter中无法转发请求
struts2 Filter中无法转发请求 项目升级struts2版本为最新以修复漏洞,由于一些历史原因,部分访问在升级后访问404,直接对历史代码改造代价太大. 于是使用拦截器对其转发.重定向,但是 ...
- 9、线性布局(Row和Column)
自定义的IconContainer void main() { runApp(MaterialApp( theme: ThemeData(primarySwatch: Colors.yellow), ...
- 【API 进阶之路】做 OCR 文字识别,谁说必须要有 AI 工程师?
摘要:有些功能还真不能光凭自己的直觉和认识,来自一线的声音才是最真实的用户需求.比方说名片录入的需求. 在公司技术委员会副主席这个位置上干了有几个月了,期间,我一方面给研发团队整理各种文档资料,做技术 ...
- 看故事学Redis:再不懂,我怀疑你是假个开发
摘要:还不懂Redis?看完这个故事就明白了! 本文转载自博客园社区<还不懂Redis?看完这个故事就明白了!>,作者:轩辕之风 我是Redis 你好,我是Redis,一个叫Antirez ...