在日常工作中,如果对Spring的事务管理功能使用不当,则会造成Spring事务不生效的问题。而针对Spring事务不生效的问题,也是在跳槽面试中被问的比较频繁的一个问题。

点击上方卡片关注我

今天,我们就一起梳理下有哪些场景会导致Spring事务生效。

Spring事务不生效总览

简单来说,Spring事务会在几种特定的场景下失效,如下图所示。


1.数据库不支持事务

Spring事务生效的前提是所连接的数据库要支持事务,如果底层的数据库都不支持事务,则Spring的事务肯定会失效。例如,如果使用的数据库为MySQL,并且选用了MyISAM存储引擎,则Spring的事务就会失效。

2.事务方法未被Spring管理

如果事务方法所在的类没有加载到Spring IOC容器中,也就是说,事务方法所在的类没有被Spring管理,则Spring事务会失效,示例如下。

public class ProductService {@Autowiredprivate 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中失效。

3.方法没有被public修饰

如果事务所在的方法没有被public修饰,此时Spring的事务会失效,例如,如下代码所示。

@Service
public class ProductService {@Autowiredprivate 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中会失效。

4.同一类中方法调用

如果同一个类中的两个方法分别为A和B,方法A上没有添加事务注解,方法B上添加了 @Transactional事务注解,方法A调用方法B,则方法B的事务会失效。例如,如下代码所示。

@Service
public class OrderService {@Autowiredprivate OrderDao orderDao;@Autowiredprivate 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中会失效。

5.未配置事务管理器

如果在项目中没有配置Spring的事务管理器,即使使用了Spring的事务管理功能,Spring的事务也不会生效。

例如,没有在项目的配置类中配置如下代码。

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
}

此时,Spring的事务就会失效。

6.方法的事务传播类型不支持事务

如果内部方法的事务传播类型为不支持事务的传播类型,则内部方法的事务在Spring中会失效。

例如,如下代码所示。

@Service
public class OrderService {@Autowiredprivate OrderDao orderDao;@Autowiredprivate 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中失效。

7.不正确的捕获异常

不正确的捕获异常也会导致Spring的事务失效,示例如下。

@Service
public class OrderService {@Autowiredprivate OrderDao orderDao;@Autowiredprivate 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事务的回滚失效问题。

8.错误的标注异常类型

如果在@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 种场景!相关推荐

  1. 聊聊Spring事务失效的12种场景,太坑人了

    前言 对于从事java开发工作的同学来说,spring的事务肯定再熟悉不过了. 在某些业务场景下,如果一个请求中,需要同时写入多张表的数据.为了保证操作的原子性(要么同时成功,要么同时失败),避免数据 ...

  2. spring事务失效的11种场景

    1 访问权限问题: java的访问权限有4种:private.default.protected.public,它们的权限从左到右,以此变大.如果在开发中,将事务方法定义了错误的访问权限,则事务功能会 ...

  3. Redis事务失效的三种场景

    文章目录 Redis 事务失效的三种场景 命令入队报错 命令执行报错 乐观锁导致失效 Redis 事务失效的三种场景 Redis事务失败,有三种类型的失败场景: 命令入队报错 在事务提交之前,客户端执 ...

  4. Spring事务失效的几种原因

    1.spring的事务注解@Transactional只能放在public修饰的方法上才起作用,如果放在其他非public(private,protected)方法上,虽然不报错,但是事务不起作用 2 ...

  5. Spring事务失效 -方法内部调用

    首先感谢网友的文章 Spring事务失效的2种情况 JDK动态代理给Spring事务埋下的坑 前提知识: 两个前提 1 注解使用 spring容器的事务管理注解 @org.springframewor ...

  6. 8个Spring事务失效的场景,你碰到过几种?

    前言 作为Java开发工程师,相信大家对Spring种事务的使用并不陌生.但是你可能只是停留在基础的使用层面上,在遇到一些比较特殊的场景,事务可能没有生效,直接在生产上暴露了,这可能就会导致比较严重的 ...

  7. 详解spring事务失效和回滚失败的场景

    详解spring事务失效和回滚失败的场景 详解spring事务失效和回滚失败的场景 前言 一 .事务不生效 1.访问权限问题 2. 方法用final修饰 3.方法的内部调用 3.1 新加一个Servi ...

  8. spring中事务失效的几种情况

    下面简单介绍下,spring中常见的事务失效的几种情况.让我们在开发的过程避免这些情况,写出正确而且优雅的代码. 文章目录 数据库引擎不支持,mysql需要InnoDB 方法必须是public的 方法 ...

  9. 详细整理Spring事务失效的具体场景及解决方案

    实际项目开发中,如果涉及到多张表操作时,为了保证业务数据的一致性,大家一般都会采用事务机制:好多小伙伴可能只是简单了解一下,遇到事务失效的情况,便会无从下手,溪源此篇文章给大家整理了一下常见Sprin ...

最新文章

  1. 两只小熊队高级软件工程第七次作业敏捷冲刺7
  2. SQL 性能优化梳理,干掉慢SQL!
  3. idea配置Run Dashboard的方法(亲测有效)
  4. struts 2中为什么抽象包不能包含action?
  5. NumPy之:理解广播
  6. 研讨会 | CCF TF 第 17 期:认知计算产业化落地
  7. [实战] 用数人云,部署弹性 ELK 集群就五步 1
  8. 维度退化(数据仓库)
  9. AutoCAD.net: 用于ObjectARX 开发的Visual Studio 智能感知文件
  10. 计算机毕业设计中用Java 实现系统权限控制
  11. 配置百度云CDN加速
  12. 第三方验收测试报告怎么做?
  13. mbot机器人自动超声波模式程序_测评 | mBot机器人秒变编程达人
  14. python编写手机病毒_十行代码--用python写一个USB病毒
  15. 证券交易所的运作系统
  16. 基于FPGA的简易 DDS 信号发生器的设计
  17. 强大免费的在线格式转换工具,三步轻松完成。
  18. C++程序中如何执行cmd命令
  19. 懂得感恩的人,运气都不会太差
  20. UT源码_105032014126(改)

热门文章

  1. 10. Python面向对象
  2. 辛苦俩月总结的面试题,掌握它怼翻面试官不是梦~
  3. testflight进行用户的beta测试
  4. 关于Linux网卡调优之:RPS (Receive Packet Steering)
  5. SVN命令行更新代码
  6. UOJ#31 【UR #2】猪猪侠再战括号序列
  7. python(33)多进程和多线程的区别
  8. parted分区介绍
  9. Eclipse快捷键-方便查找
  10. 闪存必须解决的三大问题