Spring事务的1道面试题
每次聊起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 {
@Autowired
private UserMapper userMapper;
@Transactional
public 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个动作从而保证事务回滚。
- 捕获异常,然后抛出自定义异常。
- 自行在
@Transactional
注解中增加@Transactional(rollbackFor = XxxxxxxException.class)
属性。或者直接使用rollbackFor = Exception.class
,也就免去了第一步。
- 异步线程的场景
多个线程的场景下,只需要牢记每个线程只管理自己的事务即可。每个线程都有一个独立的事务上下文,存在ThreadLocal中,所以事务信息在不同线程之间是隔离的。
- 重灾区:在同一个类中调用本类的方法
这个失效场景,是最容易出错的,而且变种还多。在同一个类中调用本类的方法时,牢记以下2点,即可破局:
- 是否会开启事务依赖此类的第一个被外部调用的方法。如果此类的第一个被外部调用的方法有
@Transactional
注解,那事务生效。 - 调用自己内部方法时,采用的是
this.xxxMethod()
的方式,这种方式是不会走AOP代理的,所以被调用的内部方法的@Transactional
注解不生效。
如果确实需要调用内部方法,并且要事务生效的话,那只能将被调用的内部方法独立到新的类中,同时交给Spring管理。
一道面试题
以上关于事务不生效的用法都比较好记,只有在同一个类中调用本类的方法
场景下存在多种变种。具体请看这道面试题。请问以下createAndUpdateUser
方法的事务生效吗?
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public final void createAndUpdateUser() { //注意这里有final修饰
createUser();
updateUserById();
}
@Transactional
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");
}
@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
的代码呢?除了面试会问......
总结
本篇主要聊了几种事务不生效的用户,有兴趣的读者可以记一下。同时,还出了一道特殊场景的面试题,供读者自行实践。希望对你有帮助!
本篇完结!欢迎 关注、加V(yclxiao)交流、全网可搜(程序员半支烟)
原文链接:https://mp.weixin.qq.com/s/V5KpVk0kDhc9vWctOy7X9A
Spring事务的1道面试题的更多相关文章
- 一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 31.线程池复用的原理 32.spring是什么? 33.对Aop的理解 34.对IOC的理解 35.BeanFactor ...
- JavaSSM框架精选50道面试题
JavaSSM框架精选50道面试题 2019年02月13日 19:04:43 EerhtSedah 阅读数 7760更多 分类专栏: 面试题 版权声明:本文为博主原创文章,遵循CC 4.0 BY- ...
- java170道面试题汇总+详细解析
2013年年底的时候,我看到了网上流传的一个叫做<Java面试题大全>的东西,认真的阅读了以后发现里面的很多题目是重复且没有价值的题目,还有不少的参考答案也是错误的,于是我花了半个月时间对 ...
- 阿里面试挂了,就因为面试官说我Spring 事务管理(器)不熟练?
前言 事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一.但除了八股文中需要熟读并背诵的那些个传播行为之外,背后的"为什么"和核心原理更为重要. 写这篇文章之前,我 ...
- ASP.NET 经典60道面试题
转:http://bbs.chinaunix.net/thread-4065577-1-1.html ASP.NET 经典60道面试题 1. 简述 private. protected. public ...
- Java 208 道面试题:第一模块答案
目前市面上的面试题存在两大问题:第一,题目太旧好久没有更新了,还都停留在 2010 年之前的状态:第二,近几年 JDK 更新和发布都很快,Java 的用法也变了不少,加上 Java 技术栈也加入了很多 ...
- 208道面试题(JVM部分暂无答案)
这是从网上看到的一套java面试题, 答案只是一个大概, 另外题目质量参差不齐, 斟酌参考(JVM的部分暂时没有答案) 一.Java 基础 JDK 和 JRE 有什么区别? 答: JDK(Java D ...
- Spring事务管理详解_基本原理_事务管理方式
1. 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交,那在没有Spring帮我们管理事 ...
- Java 208 道面试题:Java 基础模块答案
目前市面上的面试题存在两大问题:第一,题目太旧好久没有更新了,还都停留在 2010 年之前的状态:第二,近几年 JDK 更新和发布都很快,Java 的用法也变了不少,加上 Java 技术栈也加入了很多 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
随机推荐
- 【Java】Vue-Element-Admin 嵌入Druid监控面板
我看到若依做了Druid面板的嵌入,我自己的项目干脆也做一个 一.后台服务SpringBoot: Druid配置项: spring: datasource: url: jdbc:mysql://127 ...
- 【SpringBoot】09 日志集成
原来日志还分抽象层和实现层... 抽象层被称为是日志门面,实现层被称为是日志实现 门面的有: - JCL[Jakarta Commons Logging] 远古门面 - SLF4J[Simple ...
- Hession-free 的共轭梯度法的高效计算版本的部分代码(pytorch实现,实现一阶求导的一次计算重复使用)
Hession-free 的共轭梯度法的高效计算版本的部分代码(pytorch实现,实现一阶求导的一次计算重复使用) Hession-free 的共轭梯度法在求解 H*v 的时候是先求一阶导,即雅可比 ...
- 《Python数据可视化之matplotlib实践》 源码 第四篇 扩展 第十一章
图 11.2 import matplotlib.pyplot as plt import matplotlib as mpl import numpy as np plt.axes([0.1, ...
- docker 常用工具
windows 下常常需要linux环境 直接安装虚拟机不方便也浪费资源 所以直接在docker下安装一个centos 然后搭建好开发环境就是个不错的办法 一.Linux 环境 1.安装centos ...
- java关于数组的复制,反转、查找
一.数组的赋值: arr2=arr1;对于该赋值而言,地址值一样,所以arr1会随着arr2的变化而变化.这不能称作数组的复制,因为只是把地址赋过去了.地址一样,指向的是堆空间中唯一的数组实体(数值) ...
- CC2530系列课程 | IAR新建一个工程
之前录制了无线传感网综合项目实战课程,这个课程非常适合应届毕业生和想转行Linux的朋友,用来增加项目经验. 其中一部分内容是关于CC2530+zigbee的知识,后面会更新几篇关于cc2530的文章 ...
- Windows提权方式汇总
windows 提权 一.土豆(potato)家族提权 原理 土豆提权就是通过 windows 的 COM(Component Object Model,组件对象模型)类.向指定的服务器端口发送 NT ...
- APT 使用
使用 Ubuntu 包搜索器 apt 命令 功能 apt install 安装软件包 apt remove 移除软件包 apt purge 移除软件包及配置文件 apt update 刷新存储库索引 ...
- 二. Spring Boot 中的 “依赖管理和自动配置” 详解透彻到底(附+详细代码流程)
二. Spring Boot 中的 "依赖管理和自动配置" 详解透彻到底(附+详细代码流程) @ 目录 二. Spring Boot 中的 "依赖管理和自动配置" ...