导致事务@Transactional失效的5种场景!

e340d3a0f839af5f69a0d0ea6f37f37b.jpeg

作者 | 磊哥

来源 | Java面试真题解析(ID:aimianshi666)

转载请联系授权(微信ID:GG_Stone)

一个程序中不可能没有事务,而 Spring 中,事务的实现方式分为两种:编程式事务和声明式事务,又因为编程式事务实现相对麻烦,而声明式事务实现极其简单,所以在日常项目中,我们都会使用声明式事务 @Transactional 来实现事务。

@Transactional 使用极其简单,只需要在类上或方法上添加 @Transactional 关键字,就可以实现事务的自动开启、提交或回滚了,它的基础用法如下:

@Transactional 
@RequestMapping("/add")
public int add(UserInfo userInfo) {int result = userService.add(userInfo);return result;
}

@Transactional 执行流程

@Transactional 会在方法执行前,会自动开启事务;在方法成功执行完,会自动提交事务;如果方法在执行期间,出现了异常,那么它会自动回滚事务。

然而,就是看起来极其简单的 @Transactional,却隐藏着一些“坑”,这些坑就是我们今天要讲的主题:导致 @Transactional 事务失效的常见场景有哪些?

在开始之前,我们先要明确一个定义,什么叫做“失效”?

本文中的“失效”指的是“失去(它的)功效”,也就是当 @Transactional 不符合我们预期的结果时,我们就可以说 @Transactional 失效了。

那 @Transactional 失效的场景有哪些呢?接下来我们一一来看。

1.非 public 修饰的方法

当 @Transactional 修饰的方法为非 public 时,事务就失效了,比如以下代码当遇到异常之后,不能自动实现回滚:

@RequestMapping("/save")
int save(UserInfo userInfo) {// 非空效验if (userInfo == null ||!StringUtils.hasLength(userInfo.getUsername()) ||!StringUtils.hasLength(userInfo.getPassword()))return 0;// 执行添加操作int result = userService.save(userInfo);System.out.println("add 受影响的行数:" + result);int num = 10 / 0; // 此处设置一个异常return result;
}

以上程序的运行结果如下:9d6023ef0baf7b4cd800122fd6f9b8f2.png当程序出现运行时异常时,我们预期的结果是事务应该实现自动回滚,也就是添加用户失败,然而当我们查询数据库时,却发现事务并未执行回滚操作,数据库的数据如下图所示:ed143d2a734763574896b141a2bbd19b.png

2.timeout 超时

当在 @Transactional 上,设置了一个较小的超时时间时,如果方法本身的执行时间超过了设置的 timeout 超时时间,那么就会导致本来应该正常插入数据的方法执行失败,示例代码如下:

@Transactional(timeout = 3) // 超时时间为 3s
@RequestMapping("/save")
int save(UserInfo userInfo) throws InterruptedException {// 非空效验if (userInfo == null ||!StringUtils.hasLength(userInfo.getUsername()) ||!StringUtils.hasLength(userInfo.getPassword()))return 0;int result = userService.save(userInfo);return result;
}

UserService 的 save 方法实现如下:

public int save(UserInfo userInfo) throws InterruptedException {// 休眠 5sTimeUnit.SECONDS.sleep(5);int result = userMapper.add(userInfo);return result;
}

以上程序的运行结果如下:f93ae1dc30d255003a3de2affa21f39d.png数据库没有正确的插入数据,如下图所示:5455ff539c462041cf6dbb89f81a9dd8.png

3.代码中有 try/catch

在前面 @Transactional 的执行流程中,我们提到:当方法中出现了异常之后,事务会自动回滚。然而,如果在程序中加了 try/catch 之后,@Transactional 就不会自动回滚事务了,示例代码如下:

@Transactional
@RequestMapping("/save")
public int save(UserInfo userInfo) throws InterruptedException {// 非空效验if (userInfo == null ||!StringUtils.hasLength(userInfo.getUsername()) ||!StringUtils.hasLength(userInfo.getPassword()))return 0;int result = userService.save(userInfo);try {int num = 10 / 0; // 此处设置一个异常} catch (Exception e) {}return result;
}

以上程序的运行结果如下:18fb29fece24068701bc9501644afede.png此时,查询数据库我们发现,程序并没有执行回滚操作,数据库中被成功的添加了一条数据,如下图所示:82b389cc962a3137b99a2eb30dae333a.png

4.调用类内部 @Transactional 方法

当调用类内部的 @Transactional 修饰的方法时,事务是不会生效的,示例代码如下:

@RequestMapping("/save")
public int saveMappping(UserInfo userInfo) {return save(userInfo);
}
@Transactional
public int save(UserInfo userInfo) {// 非空效验if (userInfo == null ||!StringUtils.hasLength(userInfo.getUsername()) ||!StringUtils.hasLength(userInfo.getPassword()))return 0;int result = userService.save(userInfo);int num = 10 / 0; // 此处设置一个异常return result;
}

以上代码我们在添加方法 save 中添加了 @Transactional 声明式事务,并且添加了异常代码,我们预期的结果是程序出现异常,事务进行自动回滚,以上程序的执行结果如下:7149370542aaf3799a3c65fe65601242.png然而,当我们查询数据库时发现,程序执行并不符合我们的预期,添加的数据并没有进行自动回滚操作,如下图所示:93385e66506acb1aac89d335faf844cf.png

5.数据库不支持事务

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

总结

当声明式事务 @Transactional 遇到以下场景时,事务会失效:

  1. 非 public 修饰的方法;

  2. timeout 设置过小;

  3. 代码中使用 try/catch 处理异常;

  4. 调用类内部 @Transactional 方法;

  5. 数据库不支持事务。

参考 & 鸣谢

www.cnblogs.com/frankyou/p/12691463.html

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

公众号:Java面试真题解析

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

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

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

相关文章

操作系统 cpu调度_CPU调度| 操作系统

操作系统 cpu调度调度标准 (Scheduling Criteria) There are many criteria which have been suggested for comparing the CPU scheduling algorithms. The characteristics which are used for comparison and then used to determine the best algorithms, for this some of…

IOS中KVO模式的解析与应用

最近老翁在项目中多处用到了KVO,深感这种模式的好处。现总结如下: 一、概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察…

使用 lambda 实现超强的排序功能

我们在系统开发过程中,对数据排序是很常见的场景。一般来说,我们可以采用两种方式:借助存储系统(SQL、NoSQL、NewSQL 都支持)的排序功能,查询的结果即是排好序的结果查询结果为无序数据,在内存中…

java 的23种设计模式 之单身狗和隔壁老王的故事

2019独角兽企业重金招聘Python工程师标准>>> 觉得代码写的别扭了,回头翻翻java 的23种设计模式。today,额,这么晚了,困了。就弄个最简单的单例模式吧。单例模式:俗称单身狗 package singleton; public class SingleTon { private …

使用python学线性代数_二项式过程| 使用Python的线性代数

使用python学线性代数When we flip a coin, there are two possible outcomes as head or tail. Each outcome has a fixed probability of occurrence. In the case of fair coins, heads and tails each have the same probability of 1/2. In addition, there are cases in …

工作中常见的 6 种设计模式,你用过几种?

前言 哈喽,大家好。平时我们写代码呢,多数情况都是流水线式写代码,基本就可以实现业务逻辑了。如何在写代码中找到乐趣呢,我觉得,最好的方式就是:使用设计模式优化自己的业务代码。今天跟大家聊聊日常工作中…

这12款idea插件,能让你代码飞起来!

前言基本上每个程序员都会写代码,但写代码的速度不尽相同。为什么有些人,一天只能写几百行代码?而有些人,一天可以写几千行代码?有没有办法,可以提升开发效率,在相同的时间内,写出更…

node js 开发网站_使用Node JS开发网站

node js 开发网站You will have your own fully functional website running on "localhost" after going through this article. 阅读完本文后,您将在“ localhost”上运行自己的功能齐全的网站 。 Basic knowledge of JavaScript and HTML is a prereq…

Java:LocalDate / LocalDateTime加减时间

在线API参考:LocalTime (Java Platform SE 8 ) 方法介绍 方法1方法1说明plusYears(long years) minusYears(long years) 返回增加/减少了年数的副本plusMonths(long months) minusMonths(long months)返回增加/减少了月数的副本plusWeeks(long weeks) minusWeeks(…

集合 List 分片的 5 种实现

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)前些天在实现 MyBatis 批量插入时遇到了一个问题,当批量插入的数据量比较大时,会导致程序执行报错&a…

使用它给 ​xxl-job 添加任务,太爽了

xxl-job是一款非常优秀的任务调度中间件,轻量级、使用简单、支持分布式等优点,让它广泛应用在我们的项目中,解决了不少定时任务的调度问题。我们都知道,在使用过程中需要先到xxl-job的任务调度中心页面上,配置执行器ex…

dubboSPI机制浅谈

2019独角兽企业重金招聘Python工程师标准>>> 本文重点讲述SPI机制,从jdk和dubbo 1、jdk spi机制 2、dubbo spi实现 首先spi是什么? SPI是为某个接口寻找服务实现的机制。为了实现在模块装配的时候能不在…

彻底搞懂 SpringBoot 中的 starter 机制

前言我们都知道,Spring的功能非常强大,但也有些弊端。比如:我们需要手动去配置大量的参数,没有默认值,需要我们管理大量的jar包和它们的依赖。为了提升Spring项目的开发效率,简化一些配置,Sprin…

Java 中验证时间格式的 4 种方法

大家好,今天咱们来讲一下,Java 中如何检查一个字符串是否是合法的日期格式?为什么要检查时间格式?后端接口在接收数据的时候,都需要进行检查。检查全部通过后,才能够执行业务逻辑。对于时间格式&#xff0c…

Redis 实现分布式锁的 7 种方案

前言日常开发中,秒杀下单、抢红包等等业务场景,都需要用到分布式锁。而Redis非常适合作为分布式锁使用。本文将分七个方案展开,跟大家探讨Redis分布式锁的正确使用方式。如果有不正确的地方,欢迎大家指出哈,一起学习一…

css复选框样式_使用CSS样式复选框

css复选框样式Introduction: 介绍: Sometimes we want to develop a website or web page that would contain a form and through that form, we want to get some information from the user. Now that information could be of any type depending on the kind …

javascript对话框_JavaScript中的对话框

javascript对话框JavaScript对话框 (JavaScript Dialog Boxes) Dialog boxes are a great way to provide feedback to the user when they submit a form. In JavaScript, there are three kinds of Dialog boxes, 对话框是向用户提交表单时提供反馈的好方法。 在JavaScript中…

排查死锁的 4 种工具,秀~

作者 | 磊哥来源 | Java中文社群(ID:javacn666)转载请联系授权(微信ID:GG_Stone)死锁(Dead Lock)指的是两个或两个以上的运算单元(进程、线程或协程)&#xf…

MySQL 常见的 9 种优化方法

大家好,我是磊哥!今天给大家分享一些简单好用的数据库优化方式!1、选择最合适的字段属性Mysql是一种关系型数据库,可以很好地支持大数据量的存储,但是一般来说,数据库中的表越小,在它上面执行的…

oracle中dbms_DBMS中的实例和架构

oracle中dbms1)实例 (1) Instances) What is the Instance? If we look towards it in real life, we refer instance as an occurrence of something at a particular moment of time. In Database Management system, there are a lot of changes occurring over time to th…