首页 > 其他分享 >面试突击86:SpringBoot 事务不回滚?怎么解决?

面试突击86:SpringBoot 事务不回滚?怎么解决?

时间:2022-09-25 21:13:30浏览次数:94  
标签:回滚 SpringBoot 解决方案 Transactional 事务 面试 自动 86 public

在 Spring Boot 中,造成事务不自动回滚的场景有很多,比如以下这些:

  1. 非 public 修饰的方法中的事务不自动回滚;
  2. 当 @Transactional 遇上 try/catch 事务不自动回滚;
  3. 调用类内部的 @Transactional 方法事务不自动回滚;
  4. 抛出检查异常时事务不自动回滚;
  5. 数据库不支持事务,事务也不会自动回滚。

那么对于上面的这些场景,我们应该如何解决呢?接下来我们一一来看。

1.非 public 方法解决方案

非 public 方法中事务不回滚的直接原因是,在非 public 方法上添加的 @Transactional 关键字是无效的,也就是此方法本身是以非事务的方式运行的,所以它当然不会自动回滚事务了。

因为 @Transactional 使用的是 Spring AOP 实现的,而 Spring AOP 是通过动态代理实现的,而 @Transactional 在生成代理时会判断,如果方法为非 public 修饰的方法,则不生成代理对象,这样也就没办法自动回滚事务了,它的部分实现源码如下:

protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
   // Don't allow no-public methods as required.
   // 非 public 方法,设置为 null
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }
   // 后面代码省略....
 }

此问题的解决方案是将方法的权限修饰符改为 public 即可。

2.try/catch 解决方案

当程序中出现了 try/catch 代码时,事务不会自动回滚,这是因为 @Transactional 注解在其实现时,需要感知到异常才会自动回滚,而用户自行在代码中加入了 try/catch 之后,@Transactional 就无法感知到异常了,那么也就不能自动回滚事务了。

此问题的解决方案有两种:一种是在 catch 中将异常重新抛出去,另一种是使用代码手动将事务回滚。

解决方案1:将异常重新抛出

image.png

解决方案2:使用代码手动回滚事务

除了解决方案 1 这种不是很友好的回滚事务的方式之外,我们还可以选择更加友好的,不报错,但可以回滚事务的方式,其核心实现代码如下:
image.png

3.调用内部 @Transactional 方法解决方案

调用类内部 @Transactional 的方法不自动回滚事务的原因是,@Transactional 是基于 Spring AOP 实现的,而 Spring AOP 又是基于动态代理实现的,而当调用类内部的方法时,不是通过代理对象完成的,而是通过 this 对象实现的,这样就绕过了代理对象,从而事务就失效了。

此时我们的解决方案是给调用的方法上也加上 @Transactional,具体实现代码如下:
image.png

4.检查异常的事务解决方案

所谓的检查异常(Checked Excetion)指的是编译器要求开发者必须处理的异常,如下图所示:
image.png
检查异常不回滚事务的原因是因为,@Transactional 默认只回滚运行时异常 RuntimeException 和 Error,而对于检查异常默认是不回滚的。

此问题的解决方案是给 @Transactional 注解上,添加 rollbackFor 参数并设置 Exception.class 值即可,具体实现代码如下:
image.png

5.数据库不支持事务的解决方案

当我们在程序中添加了 @Transactional,相当于给调用的数据库发送了:开始事务、提交事务、回滚事务的指令,但是如果数据库本身不支持事务,比如 MySQL 中设置了使用 MyISAM 引擎,因为它本身是不支持事务的,这种情况下,即使在程序中添加了 @Transactional 注解,那么依然不会有事务的行为,也就不会执行事务的自动回滚了。

在这种情况下,我们只需要设置 MySQL 的引擎为 InnoDB 就可以解决问题了,因为 InnoDB 是支持事务的,当然 MySQL 5.1 之后的默认引擎就是 InnoDB,引擎的设置分为以下两种情况:
在新建表时设置数据库引擎:
image.png
在修改表时设置数据库引擎:
image.png

PS:也就是数据库的引擎是和表直接相关的,我们只需要正确的设置引擎之后,事务就可以正常的执行了。

总结

本文我们介绍了 5 种事务不自动回滚的场景和相应的解决方案,开发者应该根据自己的实际情况,选择合适自己解决方案进行处理。

是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

面试合集:https://gitee.com/mydb/interview

标签:回滚,SpringBoot,解决方案,Transactional,事务,面试,自动,86,public
From: https://www.cnblogs.com/vipstone/p/16728918.html

相关文章

  • Maven 创建SpringBoot
    <?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:sc......
  • SpringBoot Maven 继承
    父项目<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"......
  • 计算机毕业设计 SpringBoot+Vue招投标系统 招标系统 投标系统 招标采购系统Java Vue M
    ......
  • 代码随想录 两两交换链表中的节点(LeetCode 24), 删除链表的倒数第N个节点(LeetCode 1
    两两交换链表中的节点题目给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。题目链接示例:题解对于奇数个节点,最后一个节点不交换。结束条件:对于奇数个节......
  • Redis面试题
    1.项目中是否使用过redis?为什么要使用redis?使用过之前使用的都是修改某个value值,如登录账号被锁定30分钟,查看还剩余的时间,或者想将账号由锁定状态更新为未锁定状态,删......
  • SpringBoot集成onlyoffice实现word文档编辑保存
    说明onlyoffice为一款开源的office在线编辑组件,提供word/excel/ppt编辑保存操作以下操作均基于centos8系统,officeonly镜像版本7.1.2.23镜像下载地址:https://yunpan.360......
  • camunda_06_quickstart_springboot
    目标在SpringBoot项目中集成Camunda流程引擎,并启动启动一个流程实例了解集成Camunda需要调整哪些配置pom.xml最简单的方式是使用camunda的SpringBoot向导生成......
  • 55道软件测试精品面试题分享!内附答案!
    1、你的测试职业发展是什么?测试经验越多,测试能力越高。所以我的职业发展是需要时间积累的,一步步向着高级测试工程师奔去。而且我也有初步的职业规划,前3年积累测试经验,按......
  • 三一重工面试
    9.25一面(20min)自我介绍主要用什么语言Final修饰符抽象类与普通类、抽象类能否用final修饰String类的常用方法TCP和UDP的区别HTTP的get和post在项目中如何使用的HT......
  • 前端高频面试题及答案整理(一)
    diff算法是怎么运作每一种节点类型有自己的属性,也就是prop,每次进行diff的时候,react会先比较该节点类型,假如节点类型不一样,那么react会直接删除该节点,然后直接创建新的节......