Spring事务的一道面试题

每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。

原理

Spring事务的原理是:通过AOP切面的方式实现的,也就是通过代理模式去实现事务增强。

具体过程是:对包含@Transactional注解的方法进行拦截,然后重写,重新在方法里加入异常回滚的逻辑。而且,每个线程都是独立管理自己的事务,相互隔离。

原理简单,使用起来也简单,也就是在方法上打上@Transactional注解,然后事务就正常生效了。也很少有人去验证异常情况下是否能真正的回滚。

Spring事务让我熟悉的地方是哪哪看起来都简单,让我陌生的地方使用时的变种较多,有时候莫名其妙的不生效。

源码

以上原理的相关源码如下:

实践出真知

但是 [半支烟] 偶尔会在编码过程中发现有些场景下的事务是失效的,总有些情况让你想不到,总有一些坑点等你去跳。

[半支烟] 觉得验证事务的最好方式就是:记住基本原则 + 动手实践。记住基本原则可以快速处理常规问题,动手实践可以验证偏门问题或者不确定的问题。

几种事务不生效的用法

如下是常见的几种Spring事务不生效的用法,有空的读者一定要牢记,对日常编码很有帮助,同时面试时也能说几句。

  • private方法

Spring是通过AOP代理的方式实现事务增强的,但是private方法无法被代理,所以在private方法上打@Transactional注解是不生效的。

  • final、static修饰的方法

和private方法类似,final和static修饰的方法也无法被代理,所以@Transactional注解也不生效。

因为,static是属于类方法,final修饰的方法无法被重写,自然也就无法植入事务增强代码。

  • Bean对象没有被Spring托管

某个类一定要被Spring托管,那才能通过@Transactional注解去增强事务。如果只有@Transactional注解,而没有把类交给Spring托管,事务也是不生效的。类似如下情况:

// 此处没有@Service注解,此类不被spring托管,及时有@Transactional也不生效
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactionalpublic final void createAndUpdateUser() {createUser();updateUserById();}public void createUser() {User user = new User();user.setId(2L);user.setName("test2");user.setEmail("test2" + "@test.com");userMapper.insert(user);System.out.println("create user");}public void updateUserById() {User user = userMapper.findById(1L);user.setName("admin1");userMapper.update(user);int i = 1 / 0; // 此处会抛出异常System.out.println("update user");}
}

  • 异常被吞掉

如果在业务代码里,通过try......catch捕获了异常,同时又没有继续抛出异常时,Spring事务也是不生效的。

因为代理增强的逻辑就是要发现了异常,才能回滚事务。如果异常被方法本身吞掉了,则代理会认为没有异常,从而无法回滚。

  • 非RuntimeException异常

Spring事务默认会回滚RuntimeException 及其子类,以及 Error 类型的异常。如果是其余异常,则不会回滚。源码处可见:

这种非RuntimeException异常场景下,需要做2个动作从而保证事务回滚。

  1. 捕获异常,然后抛出自定义异常。

  2. 自行在@Transactional注解中增加@Transactional(rollbackFor = XxxxxxxException.class)属性。或者直接使用rollbackFor = Exception.class,也就免去了第一步。

  • 异步线程的场景

多个线程的场景下,只需要牢记每个线程只管理自己的事务即可。每个线程都有一个独立的事务上下文,存在ThreadLocal中,所以事务信息在不同线程之间是隔离的。

  • 重灾区:在同一个类中调用本类的方法

这个失效场景,是最容易出错的,而且变种还多。在同一个类中调用本类的方法时,牢记以下2点,即可破局:

  1. 是否会开启事务依赖此类的第一个被外部调用的方法。如果此类的第一个被外部调用的方法有@Transactional注解,那事务生效。

  2. 调用自己内部方法时,采用的是this.xxxMethod()的方式,这种方式是不会走AOP代理的,所以被调用的内部方法的@Transactional注解不生效。

如果确实需要调用内部方法,并且要事务生效的话,那只能将被调用的内部方法独立到新的类中,同时交给Spring管理。

一道面试题

以上关于事务不生效的用法都比较好记,只有在同一个类中调用本类的方法场景下存在多种变种。具体请看这道面试题。请问以下createAndUpdateUser方法的事务生效吗?

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactionalpublic final void createAndUpdateUser() { //注意这里有final修饰createUser();updateUserById();}@Transactionalpublic void createUser() {User user = new User();user.setId(2L);user.setName("test2");user.setEmail("test2" + "@test.com");userMapper.insert(user);System.out.println("create user");}@Transactional(rollbackFor = Exception.class)public void updateUserById() {User user = userMapper.findById(1L);user.setName("admin1");userMapper.update(user);int i = 1 / 0; // 此处会抛出异常System.out.println("update user");}
}

如果按照重灾区:在同一个类中调用本类的方法里提到的2个原则,则事务全部生效。

如果按照final、static修饰的方法里提到的原则,则事务全部不生效。

那结果如何呢?结果是以上方法的事务全部生效。

为什么呢?这里在补充一个原则:final修饰的方法如果带上@Transactional注解,事务情况按照被调用的方法自身的事务托管情况而定。

因为以上代码中的createUser方法和updateUserById方法,都有@Transactional注解,所以都生效。

这种特殊情况也实在是让人瞠目,不过只需要牢记以上几种不生效的用法即可,谁没事儿写这种@Transactional + final的代码呢?除了面试会问......

总结

本篇主要聊了几种事务不生效的用户,有兴趣的读者可以记一下。同时,还出了一道特殊场景的面试题,供读者自行实践。希望对你有帮助!

文章转载自:程序员半支烟

原文链接:https://www.cnblogs.com/mangod/p/18456140

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug

created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区,Zotero 中文维护小组,Zotero 插件,Zotero 中文 CSL 样式 数…

室联人形机器人:家政服务任务结构化、技术要点、深入应用FPGA的控制系统框架设计(整合版)

目录: 0 引言 1 人形机器人对室内家政服务任务的结构化 1.1人形机器人在室内家政服务中的比较优势 1.1.1 人形机器人拟人性的7个维度 1.1.2 拟人性在室内家政服务工作中的比较优势 1.1.3 潜在的重要用户:宠物爱好者 1.2 居所室内环境的特征与结构…

基于stm23的智慧宿舍系统 (DAY10)_小程序

好久没记录开发进度了,今天小程序差不多开发完了,UI这块算是比较常见了,主要功能是能连接onenet查看设备上传的数据,同时也能对设备进行一些控制下面是几个主要的函数,功能比较简单 wx.request({url: ${apiBaseUrl}/t…

ruoyi-nbcio为安全起见actuator为仅暴露health端点

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: h…

Vant UI +Golang(gin) 上传文件

前端基本用法:点击查看 实现代码: const afterRead (file) > {console.log(file);//set content-type to multipart/form-dataconst formData new FormData();formData.append("file", file.file);request.POST("/api/v1/users/up…

鸿蒙分享(一):添加模块,修改app名称图标

码仓库:https://gitee.com/linguanzhong/share_harmonyos 鸿蒙api:12 新建公共模块common 在entry的oh-package.json5添加dependencies,引入common模块 "dependencies": {"common": "file:../common" } 修改app名称&…

图像处理网络中的模型水印

论文信息:Jie Zhang、Han Fang、Weiming Zhang、Wenbo Zhou、Hao Cui、Hao Cui、Nenghai Yu:Model Watermarking for Image Processing Networks 本文首次提出了图像处理网络中深度水印问题,将知识产权问题引入图像处理模型 提出了第一个深…

C# Decimal

文章目录 前言1. Decimal 的基本特性2. 基本用法示例3. 特殊值与转换4. 数学运算示例5. 精度处理示例6. 比较操作示例7. 货币计算示例8. Decimal 的保留小数位数9. 处理 Decimal 的溢出和下溢10. 避免浮点数计算误差总结 前言 decimal 是 C# 中一种用于表示高精度十进制数的关键…

网络安全协议基本问题

Http和Https协议的端口号: Http:80 Https:443 网络监听: 网络监听是一种监视网络状态、数据流程以及网络上信息传输的工具,它可以将网络界面设定成监听模式,并且可以截获网络上所传输的信息。但是网络监…

贪心算法part05

文章参考来源代码随想录 (programmercarl.com) 56. 合并区间 本题和前几题类似,都是判断上一个元素的右边界与当前元素的左边界大小关系 但是需要注意是:本题需要更新结果数组元素的右边界,因此比较的是数组最后一个元素右边界与当前元素左…

【Spring篇】初始Spring MVC框架之Spring MVC入门程序编写

🧸安清h:个人主页 🎥个人专栏:【计算机网络】【Mybatis篇】【Spring篇】 🚦作者简介:一个有趣爱睡觉的intp,期待和更多人分享自己所学知识的真诚大学生。 目录 🎯Spring MVC概述 …

深度学习图像增强介绍

目录 一、引言二、常用数据增广方法三、图像变换类3.1 AutoAugment3.2 RandAugment 四、图像裁剪类4.1 Cutout4.2 RandomErasing4.3 HideAndSeek 五、图像混叠5.1 Mixup5.2 Cutmix 六、结论 一、引言 在图像分类任务中,图像数据的增广是一种常用的正则化方法&#…

Python办公—DataMatrix二维条码制作

目录 专栏导读1、库的介绍2、库的安装3、核心代码4、完整代码总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——>Python办公自动化专…

SAP导出表结构并保存到Excel 源码程序

SAP导出表结构并保存到Excel,方便写代码时复制粘贴 经常做接口,需要copy表结构,找到了这样一个程程,特别有用。 01. 先看结果

基于Java Springboot在线招聘APP且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 微信…

Hbase整合Mapreduce案例1 hdfs数据上传至hbase中——wordcount

目录 整合结构准备java API 编写pom.xmlMain.javaMap.javaReduce 运行 整合结构 准备 上传hdfs data.txt数据 data.txt I am wunaiieq QAQ 123456 Who I am In todays interconnected world the role of technology cannot be overstated It has revolutionized the way we …

基于openzeppelin插件的智能合约升级

一、作用以及优点 部署可升级合约,插件自动部署proxy和proxyAdmin合约,帮助管理合约升级和交互;升级已部署合约,通过插件快速升级合约,脚本开发方便快捷;管理代理管理员的权限,只有proxyAdmin的…

MQ的基本概念

1 MQ的基本概念 RabbitMQ是一个开源的消息代理和队列服务器,它使用Erlang语言编写并运行在多种操作系统上,如Linux、Windows等。RabbitMQ可以接收、存储和转发消息(也称为“事件”)到连接的客户端。它适用于多种场景,…

【计算机网络】实验11:边界网关协议BGP

实验11 边界网关协议BGP 一、实验目的 本次实验旨在验证边界网关协议(BGP)的实际作用,并深入学习在路由器上配置和使用BGP协议的方法。通过实验,我将探索BGP在不同自治系统之间的路由选择和信息交换的功能,理解其在互…

HDD 2025年技术趋势深度分析报告

随着数据量的指数级增长以及人工智能(AI)、物联网(IoT)、云计算和视频监控等领域的需求激增,硬盘驱动器(HDD)行业正面临着前所未有的挑战与机遇。本报告旨在深入剖析2025年HDD技术的发展方向&am…