html调用接口_Spring 自调用事务失效,你是怎么解决的?

3342cecf8714a13bb97df6e74c53e21f.png

前言

" 相信大家都遇到一种事务失效场景,那就是 Spring 自调用,就是在 Service 方法内,调用另一个加 @Transactional 注解的方法,发现事务失效,这时候你是怎么解决的呢? "

1

事情回顾

那是一个我忘了天气咋样的下午,突然蹦出一个小红点,嗯~ 挺着急的小红点。

94cbdadb8ab5a2a863c6ed57df408995.png

原来是事务失效了!

莫慌!莫慌!

2841cc35a8654c019c166bc7b3ae6f0b.png
33fa9ebed70be074ee9d17bf02024088.png
7fe59aaf4b628d70b78e19fbba28e20d.png

最后小伙伴选择了抽走,是我的工具类不香了么?

7b2d16b975ce653b6586c54865a16cf4.png

当然故事的结果是完美的,问题解决了。

13f6191d268442c1308751f0ad09f126.png

2

事务

在开发中涉及到同时操作多个表的时候,要保证两个操作要么一起成功,要么一起失败,这时候就需要用到事务。

现在一般使用的都是基于 @Transactional 注解的声明式事务

而事务使用过程中有以下几个注意事项:

  1. 事务只能应用到 public 方法上才会有效;
  2. 事务需要从外部调用,Spring 自调用会失效;
  3. 建议事务注解 @Transactional 一般添加在实现类上。

当然这几句话不是说我的,人家官方文档可是明确说明的!

565ed314500daa6046cf337ea43e39df.png

这里可是说明了应仅将 @Transactional 注解应用于具有公开可见性的方法。如果对受 protected, private o或 package-visible 修饰的方法使用,则不会引发任何错误,但是被注解的方法不会显示已配置的事务设置。

说白了,就是你用了,不会报错,但是不生效!

05726a9bf68150fa8a5dd7123ca0860f.png

至于建议加在实现类上,这个只是建议,不过如果加在接口类或接口方法上时,只有配置基于接口的代理才会生效。所以这块还是老老实实的加在实现类或实现类方法上吧。

ba43f4905d93319aed4b63f686cf9eff.png

因为代理模式只拦截通过代理传入的外部方法调用,所以自调用事务是不生效的。

官方的解释还是比较简单明了的,虽然我看不懂,但是不影响我截图。

那我还是再截一个吧……

9b354a61bdc764f5af994e6530e17c29.png

3

实际使用

但是在开发中,小伙伴们往往会遇到这种情况!

7c2a8a7722037ed77fa9d127843c5284.png

本来自己写的代码就一坨坨的又臭又长,里面有各种验签、验参、查询、验证等等,就想着来个事务,让事务包裹的范围最小,仅仅在同时更新的时候加上事务吧!

6bd92dce644ff3a34adf60302596f701.png

这么写,咦~ IDEA 报错了,好像不能 private 修饰,那我改成 public。

很显然事务是不生效的。

把更新的代码放到又臭又长的代码里面,让它变得更臭更长,然后用 @Transactional 注解一加。完美解决!

1776b18d60459c6a90cee2d9e5482748.png

请放过那坨代码吧!来看看下面的办法。

解决方案 1

ef1e1814b0645199ef697ea4428281a4.png

那我改成外部调用不就行了么?


再声明一个 Service,把更新表的逻辑放过去。

我一般就喜欢使用这个办法。

解决方案 2

使用编程式事务,前面说了,使用声明式事务时,又这又那,我换一种总可以吧!

babc182ef9daf0d47d92c646213fdd8e.png

你看,我还把方法改成 private 修饰了,事务也生效。完美解决!

64306d80a591868f59980856a7794e1f.png

其实这个方法也很不错哦!

解决方案 3

又想用注解,又想自调用怎么办?

f81a6915fc1c21ac891268f85f4f3d33.png

不过... 麻烦一点还是可以的。

咱们可以参考编程式事务的方式,不就是不让自调用么,我调外部方法,然后外部方法再给我调回来不就可以了。

@Componentpublic 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 表达式。

0f8ecc3044a11a9cabbd1199a03050ad.png

当然基于这个版本也可以做一个迭代,就是使用静态方法调用,不用每次都用 @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);    }}
dc7c1c0d02e3a510ea5dc20b5f9ff21a.png

这样通过工具类 TransactionalUtils 便可以直接调用静态方法的方式执行事务操作。

4

总结

结束语

本文主要介绍为什么会遇到事务失效,以及事务失效的避免方式,同时提供了三种方式来解决自调用事务失效的问题。不足之处,欢迎指正。

相关资料

[1] Spring 文档:

https://docs.spring.io/spring-framework/docs/5.3.0/reference/html/data-access.html#transaction-declarative-annotations

- -


作者:刘志航,一个宅宅的北漂程序员。

公众号:liuzhihangs,记录工作学习中的技术、开发及源码笔记;时不时分享一些生活中的见闻感悟。欢迎大佬来指导!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/503064.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

unity vscode没有智能提示_GAMES101课程环境搭建(Win10+VSCode)

最近B站上看到一个不错的图形学教程,复习下图形学知识挺好的。教程地址:GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili课程主页:GAMES101: 现代计算机图形学入门作业地址:往期作业汇总帖 - 计算机图…

Java中的变量、数据类型和运算符

1. java语言是一种强类型的语言,对各种数据类型都有明确的区分,而计算机使用内存来记忆大量运算时需要使用的数据,而当声明一个变量时,即在内存中划分一块空间存储数据,而变量类型决定划分内存空间的大小。 2.基本数…

10大最高效的Java库盘点

1. Java 标准库 不用怀疑,我说的就是Java标准库,很多人都低估了或者没有完全了解Java标准库,并且不知道如何在编程的时候使用它,有些人甚至都不用它,下面说一些Java标准库的简要说明 ● java.lang:总是默…

js 加入debug后可以进入controller_写给前端的 Nest.js 教程——10分钟上手后端接口开发

前言沉默了很久,一直都没发文章,有些惭愧。最近实习结束之后回了学校,提前开始做毕业设计了。对,就是毕业设计。近两个月把 React Native、Vue 3.0 和 Nest.js 都摸了一下,大概都摸懂了。鉴于掘金已经很多优秀的 Vue 3…

ecplice中class.forname一直报错_A6v5.1升级A6v7.0报错:调用Java代码

一 背景在升级7.0过程中,针对以前SQL2000数据库(主要是以前U3升级上来的账套)会出现java调用失败的情况,导致老版本的账套无法正常升级到最新的版本。错误提示:【com.aisino.a6.update.plugin.ViewsUpdatePlugin】升级业务数据出错升级报错图…

理解 Java 核心基础精髓

1、字符串不变性 下面这张图展示了这段代码做了什么 String s "abcd"; s s.concat("ef"); 2、equals() 方法与 hashCode() 方法的区别 HashCode 被设计用来提高性能。equals() 方法与 hashCode() 方法的区别在于: 如果两个对象相等(equa…

支付退款流程设计_电商订单系统,你该如何设计

文章来自:https://baijiahao.baidu.com/s?id1602959656926168475&wfrspider&forpc作者:人人都是产品经理点击加入:PHP自学中心技术交流微信群商务合作: 请加微信(QQ):2230304070精选教程推荐技术交流微信群我们在学习中单…

Java 对象之死

如何判断对象“无用”? 关于判断对象是否无用的算法,在JVM的发展过程中出现过两种算法:一种是引用计数和根集算法。 引用计数算法 例如下图中的object1的引用计数是2,GC的时候不回收,object6、object7引用计数为0&a…

图解Java常用数据结构

最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList LinkedHashMap中的双向列表不再是回环的. HashMap中的单链表是尾插, 而不是头插入等等, 后文不再赘叙这些…

python中怎么计算_python中的加减乘除运算

python中的加减乘除运算,是学习python入门的基础,是以后进行数学计算的关键部分。包括运算表达式的写法,运算规则,加减乘除,求余,求商等等。 工具/原料 python 电脑 方法/步骤 1 1.python中的加法运算&…

c++ 模拟拖动_2020电工(中级)模拟考试题及电工(中级)模拟考试题库

题库来源:安全生产模拟考试一点通公众号小程序2020电工(中级)模拟考试题及电工(中级)模拟考试题库,包含电工(中级)模拟考试题答案解析及电工(中级)模拟考试题库练习。由安全生产模拟考试一点通公众号结合国家电工(中级)考试最新大纲及电工(中级)考试真题…

12层的bert参数量_只需一个损失函数、一个超参数即可压缩BERT,MSRA提出模型压缩新方法...

来自武汉大学、北京航空航天大学和微软亚洲研究院的这项研究为模型压缩提供了新方向。机器之心报道,参与:魔王。论文链接:https://arxiv.org/pdf/2002.02925.pdf这篇论文提出了一种新型模型压缩方法,能够通过逐步模块替换&#xf…

常用的Java快捷键有哪些

不知道Java常用的快捷键在工作的时候是非常的耽误时间的,本篇文章小编就为大家稍微整理了一些常用的Java快捷键分享给大家。 Ctrl1或F2快速修复 CtrlD快捷删除行 ShiftEnter 快速切换到下一行,在本行的任何位置都可 CtrlF11快速运行代码 Alt上下键 快速移…

bootstrap文件不能被识别_如何使用npm安装bootstrap

经过我好多次的查询和实验,总结了一下在vue项目中使用bootstrap框架,npm安装注意。bootstrap中js插件依赖于jquery,所以在这之前必须安装jquery。jquery安装1、在package.json中添加一行代码:“jquery”: “^2.2.3”"depende…

hm编码工具使用_HM集团旗下最高端品牌ARKET将进驻中国,带你看看真正的“北欧风”...

HM集团旗下最高端的品牌ARKET近日开通了微博,并宣布将在秋季进驻天猫。听到这个消息,钟爱ARKET且一直私心将它当成小众品牌好好藏着的人可能会欢呼——终于不用等待漫长的海购了!但也有相当一部分朋友一脸问号——ARKET?是啥&…

Java8特性解决空指针问题

在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示: 在这种情况下,有如下代码 这种写法,在user为null时&#x…

模拟进程创建、终止、阻塞、唤醒原语_操作系统第二章--进程的描述与控制

操作系统第二章--进程的描述与控制前趋图和程序执行前趋图前趋图是一个有向无循环图DAG,用来描述进程之间执行的前后关系初始结点:没有前趋的结点终止结点:没有后继的结点重量:表示该结点所含有的程序量或结点的执行时间程序执行顺…

对没有标记为安全的activex控件进行初始化和脚本运行_RASP攻防 —— RASP安全应用与局限性浅析...

文|【腾讯安全平台部数据安全团队】 qiye & baz 前言随着Web应用攻击手段变得复杂,基于请求特征的防护手段,已经不能满足企业安全防护需求。在2012年的时候,Gartner引入了“Runtime application self-protection”一词&#x…

java中堆和栈有什么区别?

堆和栈都是Java用来在RAM中存放数据的地方。 一、堆 (1)Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器来销毁。 (2)堆的优势是可以动态地分配内存空间,需要多少内存空间不必事先告诉编译…

台式机dp接口_精品导购:你想要的商务台式机 都在这里了!

不少公司都会为员工配备办公电脑,而公司在采购这些电脑时,兴许可能对电脑性能、存储容量等都没有研究过,只是图了价格便宜便批量采购,这就导致电脑在使用一段时间后,会频繁出现死机、运行卡顿和硬盘容量不够等情况的发…