面试官让列举Spring的事务会失效的场景,我说了8个
本文分享自华为云社区《哪些场景下Spring的事务会失效?》,作者:冰 河 。
在日常工作中,如果对Spring的事务管理功能使用不当,则会造成Spring事务不生效的问题。而针对Spring事务不生效的问题,也是在跳槽面试中被问的比较频繁的一个问题。
今天,我们就一起梳理下有哪些场景会导致Spring事务失效。
Spring事务不生效总览
简单来说,Spring事务会在几种特定的场景下失效,如下图所示。

数据库不支持事务
Spring事务生效的前提是所连接的数据库要支持事务,如果底层的数据库都不支持事务,则Spring的事务肯定会失效。例如,如果使用的数据库为MySQL,并且选用了MyISAM存储引擎,则Spring的事务就会失效。
事务方法未被Spring管理
如果事务方法所在的类没有加载到Spring IOC容器中,也就是说,事务方法所在的类没有被Spring管理,则Spring事务会失效,示例如下。
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
ProductService类上没有标注@Service注解,Product的实例没有加载到Spring IOC容器中,就会造成updateProductStockCountById()方法的事务在Spring中失效。
方法没有被public修饰
如果事务所在的方法没有被public修饰,此时Spring的事务会失效,例如,如下代码所示。
@Service
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
虽然ProductService上标注了@Service注解,同时updateProductStockCountById()方法上标注了@Transactional(propagation = Propagation.REQUIRES_NEW)注解。
但是,由于updateProductStockCountById()方法为内部的私有方法(使用private修饰),那么此时updateProductStockCountById()方法的事务在Spring中会失效。
同一类中方法调用
如果同一个类中的两个方法分别为A和B,方法A上没有添加事务注解,方法B上添加了 @Transactional事务注解,方法A调用方法B,则方法B的事务会失效。例如,如下代码所示。
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
submitOrder()方法和updateProductStockCountById()方法都在OrderService类中,submitOrder()方法上没有标注事务注解,updateProductStockCountById()方法上标注了事务注解,submitOrder()方法调用了updateProductStockCountById()方法,此时,updateProductStockCountById()方法的事务在Spring中会失效。
未配置事务管理器
如果在项目中没有配置Spring的事务管理器,即使使用了Spring的事务管理功能,Spring的事务也不会生效。
例如,没有在项目的配置类中配置如下代码。
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
此时,Spring的事务就会失效。
方法的事务传播类型不支持事务
如果内部方法的事务传播类型为不支持事务的传播类型,则内部方法的事务在Spring中会失效。
例如,如下代码所示。
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRED)
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
由于updateProductStockCountById()方法的事务传播类型为NOT_SUPPORTED,不支持事务,则updateProductStockCountById()方法的事务会在Spring中失效。
不正确的捕获异常
不正确的捕获异常也会导致Spring的事务失效,示例如下。
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRED)
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
try{
productDao.updateProductStockCountById(stockCount, id);
int i = 1 / 0;
}catch(Exception e){
logger.error("扣减库存异常:", e.getMesaage());
}
}
}
updateProductStockCountById()方法中使用try-catch代码块捕获了异常,即使updateProductStockCountById()方法内部会抛出异常,但也会被catch代码块捕获到,此时updateProductStockCountById()方法的事务会提交而不会回滚,并且submitOrder()方法的事务会提交而不会回滚,这就造成了Spring事务的回滚失效问题。
错误的标注异常类型
如果在@Transactional注解中标注了错误的异常类型,则Spring事务的回滚会失效,示例如下。
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
try{
productDao.updateProductStockCountById(stockCount, id);
}catch(Exception e){
logger.error("扣减库存异常:", e.getMesaage());
throw new Exception("扣减库存异常");
}
}
在updateProductStockCountById()方法中捕获了异常,并且在异常中抛出了Exception类型的异常,此时,updateProductStockCountById()方法事务的回滚会失效。
为何会失效呢?这是因为Spring中对于默认回滚的事务异常类型为RuntimeException,上述代码抛出的是Exception异常。
默认情况下,Spring事务中无法捕获到Exception异常,所以此时updateProductStockCountById()方法事务的回滚会失效。
此时可以手动指定updateProductStockCountById()方法标注的事务异常类型,如下所示。
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
这里,需要注意的是:Spring事务注解@Transactional中的rollbackFor属性可以指定 Throwable 异常类及其子类。
面试官让列举Spring的事务会失效的场景,我说了8个的更多相关文章
- 跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现
提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一致性Consiste ...
- 面试官:说说Spring中的事务传播行为
前言 在开发中,相信大家都使用过Spring的事务管理功能.那么,你是否有了解过,Spring的事务传播行为呢? Spring中,有7种类型的事务传播行为.事务传播行为是Spring框架提供的一种事务 ...
- 阿里面试挂了,就因为面试官说我Spring 事务管理(器)不熟练?
前言 事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一.但除了八股文中需要熟读并背诵的那些个传播行为之外,背后的"为什么"和核心原理更为重要. 写这篇文章之前,我 ...
- 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现
提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一致性Consiste ...
- 面试官:连Spring三级缓存都答不好,自己走还是我送你?
面试官:简历上写了精通Spring,那你回答一下Spring为什么用“三级缓存”去解决循环依赖? 我:.......应该有三个缓存的map结构 面试官:具体回答一下 我:平时没认真深入过 面试官:公司 ...
- 面试官:连Spring AOP都说不明白,自己走还是我送你?
前言 因为假期原因,有一段时间没给大家更新了!和大家说个事吧,放假的时候一位粉丝和我说了下自己的被虐经历,在假期前他去某互联网公司面试,结果直接被人家面试官Spring AOP三连问给问的一脸懵逼!其 ...
- 面试官一口气问了MySQL事务、锁和MVCC,我
面试官:你是怎么理解InnoDB引擎中的事务的? 候选者:在我的理解下,事务可以使「一组操作」要么全部成功,要么全部失败 候选者:事务其目的是为了「保证数据最终的一致性」. 候选者:举个例子,我给你发 ...
- 【面试】足够“忽悠”面试官的『Spring事务管理器』源码阅读梳理(建议珍藏)
PS:文章内容涉及源码,请耐心阅读. 理论实践,相辅相成 伟大领袖毛主席告诉我们实践出真知.这是无比正确的.但是也会很辛苦. 就像淘金一样,从大量沙子中淘出金子一定是一个无比艰辛的过程.但如果真能淘出 ...
- 面试官问你:MYSQL事务和隔离级别,该如何回答
一.事务 事务是由一组SQL语句组成的逻辑处理单元,是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚.事务具有以下4个属性,通常简称为事务 ...
- 面试官:什么是MySQL 事务与 MVCC 原理?
作者:小林coding 图解计算机基础网站:https://xiaolincoding.com/ 大家好,我是小林. 之前写过一篇 MySQL 的 MVCC 的工作原理,最近有读者在网站上学习的时候, ...
随机推荐
- 一行代码搞定 font-size 响应式
前言 公司要做大屏,但是大屏还要有个嵌在系统的版本,屏幕(iframe)小了但字体大了怎么办.网上找了很多代码都很长,个人参考了资料后实现了一个一行代码 font-size 响应式. TL;DR ht ...
- mysql5.5自定义函数-计算并赋值
mysql自定义函数的写法 特别注意,将全部的定义现在最前面,然后再写其他语句,因为之前将定义变量和赋值混着写,死活报错.最后一个前同事高手"邢哥"解决. DELIMITER $$ ...
- 停止 Windows 11 更新的行之有效的办法,去掉 Windows Defender 实时监控(Win 11)
用设置的方法,几乎无法达成目的.即使禁用 Windows 11 服务里的 "Windows 更新" 服务,系统也会自己将之改成手动,然后再打开. 先找到控制面板 -> 服务, ...
- git 忽略已提交(commit)的文件/文件夹
git 忽略已提交的文件或文件夹 最好是在工程一开始就编辑好 .gitignore 文件, 在第一次提交的时候仔细检查避免添加那些无用的文件 因为 .gitignore 只能对未提交过的文件起效, 也 ...
- Electron原生菜单
.markdown-body { color: rgba(56, 56, 56, 1); font-size: 15px; line-height: 30px; letter-spacing: 2px ...
- Bash—source命令&export命令&bashrc文件
当不使用 source 命令执行脚本时,会创建一个子 shell,在该子 shell 中执行完脚本后退出子 shell.不是用 export 定义的变量只对该 shell 有效,对子 shell 是无 ...
- StackGres 1.6,可私有部署的云原生数据库中间件平台工程
StackGres 数据库平台工程简介 Enterprise Postgres made easy. On Kubernetes StackGres 是 Kubernetes 的全栈 PostgreS ...
- UNCTF-Crypto wp
2020年 easy_rsa 题目 from Crypto.Util import number import gmpy2 from Crypto.Util.number import bytes_t ...
- 01 MyBatis第一个应用程序
1.MyBatis是什么? mybatis是一个基于java的持久层框架. 2.什么是持久化 数据由瞬态状态变为持久状态. 3.持久层: 完成持久化工作的代码块. -- DAO层,将数据存到数据库 4 ...
- Educational Codeforces Round 26 Problem A
A. Text Volume time limit per test 1 second memory limit per test 256 megabytes input standard input ...