Spring 自调用事务失效,你是怎么解决的?
前言
相信大家都遇到一种事务失效场景,那就是 Spring 自调用,就是在 Service 方法内,调用另一个加
@Transactional
注解的方法,发现事务失效,这时候你是怎么解决的呢?公众号:『 刘志航 』,记录工作学习中的技术、开发及源码笔记;时不时分享一些生活中的见闻感悟。欢迎大佬来指导!
事情回顾
那是一个我忘了天气咋样的下午,突然蹦出一个小红点,嗯~ 挺着急的小红点。
原来是事务失效了!
莫慌!莫慌!
最后小伙伴选择了抽走,是我的工具类不香了么?
当然故事的结果是完美的,问题解决了。
事务
在开发中涉及到同时操作多个表的时候,要保证两个操作要么一起成功,要么一起失败,这时候就需要用到事务。
现在一般使用的都是基于 @Transactional
注解的声明式事务。
而事务使用过程中有以下几个注意事项:
- 事务只能应用到 public 方法上才会有效;
- 事务需要从外部调用,Spring 自调用会失效;
- 建议事务注解 @Transactional 一般添加在实现类上。
当然这几句话不是说我的,人家官方文档可是明确说明的!
这里可是说明了应仅将 @Transactional 注解应用于具有公开可见性的方法。如果对受 protected, private o或 package-visible 修饰的方法使用,则不会引发任何错误,但是被注解的方法不会显示已配置的事务设置。
说白了,就是你用了,不会报错,但是不生效!
至于建议加在实现类上,这个只是建议,不过如果加在接口类或接口方法上时,只有配置基于接口的代理才会生效。所以这块还是老老实实的加在实现类或实现类方法上
吧。
因为代理模式只拦截通过代理传入的外部方法调用,所以自调用事务是不生效的。
官方的解释还是比较简单明了的,虽然我看不懂,但是不影响我截图。
那我还是再截一个吧……
实际使用
但是在开发中,小伙伴们往往会遇到这种情况!
本来自己写的代码就一坨坨的又臭又长,里面有各种验签、验参、查询、验证等等,就想着来个事务,让事务包裹的范围最小,仅仅在同时更新的时候加上事务吧!
这么写,咦~ IDEA 报错了,好像不能 private
修饰,那我改成 public
。
很显然事务是不生效的。
把更新的代码放到又臭又长
的代码里面,让它变得更臭更长,然后用 @Transactional
注解一加。完美解决!
请放过那坨代码吧!来看看下面的办法。
解决方案 1
那我改成外部调用不就行了么?
再声明一个 Service,把更新表的逻辑放过去。
我一般就喜欢使用这个办法。
解决方案 2
使用编程式事务
,前面说了,使用声明式事务
时,又这又那,我换一种总可以吧!
你看,我还把方法改成 private
修饰了,事务也生效。完美解决!
其实这个方法也很不错哦!
解决方案 3
又想用注解,又想自调用怎么办?
不过... 麻烦一点还是可以的。
咱们可以参考编程式事务
的方式,不就是不让自调用么,我调外部方法,然后外部方法再给我调回来不就可以了。
@Component
public class TransactionalComponent {
public interface Cell {
void run() throws Exception;
}
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void required(Cell cell) throws Exception {
cell.run();
}
}
这样的话不就可以通过 TransactionalComponent
调用了么,并且还可以使用 lambda
表达式。
当然基于这个版本也可以做一个迭代,就是使用静态方法调用,不用每次都用 @Autowired
注入一次。
public class TransactionalUtils {
private static volatile TransactionalComponent transactionalComponent;
private static synchronized TransactionalComponent getTransactionalComponent() {
if (transactionalComponent == null) {
// 从容器中获取 transactionalComponent
transactionalComponent = ApplicationContextUtils.getBean(TransactionalComponent.class);
}
return transactionalComponent;
}
public static void required(TransactionalComponent.Cell cell) throws Exception {
getTransactionalComponent().required(cell);
}
}
这样通过工具类 TransactionalUtils
便可以直接调用静态方法的方式执行事务操作。
总结
结束语
本文主要介绍为什么会遇到事务失效,以及事务失效的避免方式,同时提供了三种方式来解决自调用事务失效的问题。不足之处,欢迎指正。
相关资料
Spring 自调用事务失效,你是怎么解决的?的更多相关文章
- Spring,SpringMvc配置常见的坑,注解的使用注意事项,applicationContext.xml和spring.mvc.xml配置注意事项,spring中的事务失效,事务不回滚原因
1.Spring中的applicationContext.xml配置错误导致的异常 异常信息: org.apache.ibatis.binding.BindingException: Invalid ...
- spring+springMVC,声明式事务失效,原因以及解决办法
http://blog.csdn.net/z69183787/article/details/37819627#comments 一.声明式事务配置: <bean id="transa ...
- Spring声明式事务如何选择代理方式?
Spring声明式事务如何选择代理方式 解决方法: 1.基于注解方法: <tx:annotation-driven transaction-manager="txManager&q ...
- Spring事务Transactional和动态代理(三)-事务失效的场景
系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...
- spring声明式事务 同一类内方法调用事务失效
只要避开Spring目前的AOP实现上的限制,要么都声明要事务,要么分开成两个类,要么直接在方法里使用编程式事务 [问题] Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring ...
- Spring component-scan 的逻辑 、单例模式下多实例问题、事务失效
原创内容,转发请保留:http://www.cnblogs.com/iceJava/p/6930118.html,谢谢 之前遇到该问题,今天查看了下 spring 4.x 的代码 一,先理解下 con ...
- spring事务失效情况分析
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt113 <!--[if !supportLists]-->一.&l ...
- spring声明式事务 同一类内方法调用事务失效(转)
原文 https://blog.csdn.net/jiesa/article/details/53438342 [问题] Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring ...
- Spring事务失效的原因
http://blog.csdn.net/paincupid/article/details/51822599 Spring事务失效的原因 5种大的原因 如使用mysql且引擎是MyISAM,则事务会 ...
随机推荐
- DIV垂直滚动效果源码
<div id="demo" style="width: 300; overflow: hidden; line-height:24px; height: 100p ...
- 04 Storage and Calculation C语言中的存储和计算
文章内容来源于Programming Hub的学习记录,本人整理添加了中文翻译,如有侵权,联系本人删除 Variables C语言中的变量 Let's extend our mainfunction ...
- [Java 开源项目]一款无需写任何代码,即可一键生成前后端代码的工具
作者:HelloGitHub-小鱼干 JeecgBoot 是一款基于代码生成器的低代码开发平台,零代码开发.JeecgBoot 采用开发模式:Online Coding 模式-> 代码生成器模式 ...
- Jenkins从节点上构建自动化测试项目时报错:java.io.IOException: Unexpected termination of the channel
在mac电脑上配置了Jenkins从节点,在该从节点上构建app UI 自动化测试项目,运行一些用例后报如下错误: java.io.EOFException at java.io.ObjectInpu ...
- Android 10不能使用uiautomatorviewer定位元素的终极解决方法
Android app 元素定位除了使用Appium Inspector 外,还可以使用Android SDK 里tools中的uiautomatorviewer 工具.但今天打算使用 uiautom ...
- MeteoInfoLab脚本示例:利用比湿、温度计算相对湿度
利用比湿和温度计算相对湿度的函数是qair2rh(qair, temp, press=1013.25),三个参数分别是比湿.温度和气压,气压有一个缺省值1013.25,因此计算地面相对湿度的时候也可以 ...
- 《Kafka笔记》1、Kafka初识
目录 一.初识Kafka 1 apache kafka简介 2 消息中间件kafka的使用场景 2.1 订阅与发布队列 2.2 流处理 3 kafka对数据的管理形式 4 kafka基础架构 5 Ka ...
- linux-设置hostname
设置linux root后面的名字
- Model实体类
Model又叫实体类,这个东西,大家可能觉得不好分层.包括我以前在内,是这样理解的:UI<-->Model<-->BLL<-->Model<-->DAL ...
- codeforces#426(div1) B - The Bakery (线段树 + dp)
B. The Bakery Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought req ...