前几天我发了这篇文章《我来出个题:这个事务会不会回滚?》(https://blog.didispace.com/will-this-transcation-rollback/)

得到了很多不错的反馈,也有不少读者通过微信、群或者邮件的方式,给了我一些关于test4的回复。其中还有直接发给我测试案例,来证明我的答案是错的。

今天,我们就来一起看看test4这个争议很大的问题。如果您是刚打开这篇文章,不了解我们在讨论啥,那可以先点击查看之前的这篇《我来出个题:这个事务会不会回滚?》(https://blog.didispace.com/will-this-transcation-rollback/)。

通过这两篇文章的解析,相信你会对Spring Data JPA下的事务执行机制有质的飞跃。

为什么没回滚

先来说说,那些写了代码验证"不会回滚"的情况,把这些错误答案的原因先说清楚,然后再细说test4会回滚的情况。

根据这两天读者给我的案例或者描述清楚的一些情况,归结了一下,大家写的验证代码之所以不会回滚,主要有以下三个原因:

  1. 没有按照我题目开头说的,采用InnoDB存储引擎,用了MyISAM,不支持事务,自然不会复现。

  2. 没用按照我题目开头说的,采用JPA和JSR 303校验注解,比如:用了MyBaits,所以自然也不会复现。

  3. 定义事务的函数不是public类型,这个基础用法就不对了,事务本身就没生效

归家一下出现这些疑问的原因:没审题事务基础掌握不牢导致。关于事务基础使用的一些常见注意点,之前写过一篇文章,如果觉得这方面知识还不扎实的,建议读一读:《为什么加了@Transactional注解,事务没有回滚?》(https://blog.didispace.com/transactional-not-rollback/)

为什么写了catch,还会回滚

先来看看执行时候报的异常:

javax.validation.ConstraintViolationException: Validation failed for classes [com.didispace.chapter310.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[ConstraintViolationImpl{interpolatedMessage='个数必须在0和5之间', propertyPath=name, rootBeanClass=class com.didispace.chapter310.User, messageTemplate='{javax.validation.constraints.Size.message}'}
]at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:209) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:83) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]

这个异常是这个回滚的关键。这个异常javax.validation.ConstraintViolationException是哪里的呢?还记得以前说的JSR 303不?对的,是Bean Validation中的异常。

有的读者说这个不是RuntimeException,所以不会回滚。很显然,这类判断的都没有实际尝试一下,只要点开源码可以马上发现,这个异常就是属于RunTimeException的。

实际上,之所以会回滚,与这里使用Spring Data JPA以及Hibernate Validator有直接关系。从JPA 2.0开始,就默认支持了这些Bean Validation的实现,它提供了实体生命周期中pre-persistpre-update,pre-remove三个事件发生时来执行校验的功能。而在校验的时候,当校验失败,抛出javax.validation.ConstraintViolationException时,当前事务就会被标记为rollback

源码解析

要想了解,这其中到底发生了什么,跟踪源码是最好的方式。那么源码从哪里开始看呢?从异常日志中找线索吧。

从异常栈中找到最近的一个错误,点开看看。

错误行数在532行tx.commit(),习惯性的加上断点,这样下一次进来的时候可以看看当前情况下的各种参数情况。

同时看到下面还有个catch,既然532行出错了,那这里肯定会进,所以也加个端点,到时候可以进去看看。

执行程序,调用一下test4,执行到532行,然后进入下一步,看看会到哪里?

这个时候,会进入到org.hibernate.engine.transaction.internal.TransactionImpl,具体位置如下:

还是习惯性的,在下面两行重要位置加上断点,以便下次可以快速到这里。

继续按上看的步骤尝试下去,可以来到下图的位置:

可以看到校验异常是从271行出来的,结合278行和280行,是不是清楚这里回滚的原因了呢?

小结

当我把上一篇问题推到很多地方之后,其实还是收到了不少负面的反馈,甚至还有说我误导读者,顺便问候了下我的祖宗。这些我就不跟爱喷的读者互杠了,我是一直都推崇碰到问题,尽量多深挖一些的学习方式。虽然有的时候出现问题,确实是由于不恰当的写法导致,但如果你没有理解这个错误的原因,本质还是对其底层逻辑不够了解。如果你能从问题中找到线索,并顺藤摸瓜地探究和思考,你能够收获到的东西,远比喷我来的强。

实践出真知,当你觉得困惑的时候,不如动手写一写,调一调,很多答案就能自然浮现!如果对于test4会回滚还不够理解的读者,那就跟着我上面的步骤,一步步尝试一下,可以观察的更深入一些,你对这部分逻辑的理解就更全面了。

我们正在组建高质量的Spring技术交流群,最近这个分享的源头也是来源于群里的一次讨论。欢迎各种热爱技术的开发者加入参与讨论。这里的每个人都有自己的闪光点,互相学习,取长补短,长期坚持,愿大家都会成为自己领域里的佼佼者!

往期推荐

骚操作!阿里云直接买www.huaweicloud.com的关键词来抢生意?

Dubbo 3.0.0正式发布:应用级服务注册,跨语言的RPC协议、更好支持Kubernetes!

我来出个题:这些事务会不会回滚?大概率你会错!

警惕 Spring Boot Actuator 引发的安全问题

来活儿了!赶紧检查下代码里有没有脏话...

关注我回复「加群」,加入Spring技术交流群

原创不易,如果您觉得本文不错

欢迎转发到朋友圈,支持一下我的努力吧!

为什么catch了异常,但事务还是回滚了?相关推荐

  1. sqlsever回滚操作_sqlserver事务与回滚

    如果要在Production执行数据改动必须小心,可以使用事务提前验证一下自己写的SQL是不是你期望的.尤其是Update的where 条件有问题的话,跟新的记录就会超出预期的范围.如下面的语句,一着 ...

  2. SpringBoot 异常回滚 事务的使用___Springboot @Transactional 事务不回滚

    Springboot中事务的使用: 1.启动类加上@EnableTransactionManagement注解,开启事务支持(其实默认是开启的). 2.在使用事务的public(只有public支持事 ...

  3. 异常被 ”吃“ 掉导致事务无法回滚

    我们在处理异常时,有两种方式,要么抛出去,让上一层来捕获处理:要么把异常 try catch 掉,在异常出现的地方给处理掉.就因为有这中 try-catch,所以导致异常被 "吃" ...

  4. 【java基础】子线程任务发生异常,主线程事务如何回滚?

    文章目录 一.提出问题 二.主线程与子线程 三.线程池 四.异常的捕获 五.事务的回滚 一.提出问题 最近有一位朋友问了我这样一个问题,问题的截图如下: 这个问题问的相对比较笼统,我来稍微详细的描述下 ...

  5. spring事务——try{...}catch{...}中事务不回滚的几种处理方式

    当希望在某个方法中添加事务时,我们常常在方法头上添加@Transactional注解 @ResponseBody@RequestMapping(value = "/payment" ...

  6. java事务中使用try catch 导致事务不回滚的问题

    @Transactional注解的触发,只回滚RuntimeException和Error异常,默认不回滚非RuntimeException异常 解决方法: 1.方法前添加注解(基础的  @Trans ...

  7. mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚

    mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚 参考文章: (1)mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚 (2)https://www.cnblog ...

  8. spring@Transactional注解事务不回滚不起作用无效的问题处理

    这几天在项目里面发现我使用@Transactional注解事务之后,抛了异常居然不回滚.后来终于找到了原因. 如果你也出现了这种情况,可以从下面开始排查. 一.特性 先来了解一下@Transactio ...

  9. springboot 事务手动回滚_Spring Boot中的事务是如何实现的

    1. 概述 一直在用SpringBoot中的@Transactional来做事务管理,但是很少想过SpringBoot是如何实现事务管理的,今天从源码入手,看看@Transactional是如何实现事 ...

最新文章

  1. jquery-datatables 销毁重新渲染
  2. 中国大陆开源镜像站汇总
  3. 机器学习(K-means聚类原理以及用法)
  4. ubuntu12.04samba服务器配置
  5. Visual Studio调试技巧
  6. mysql函数大全最小,MySQL函数一览_MySQL函数全部汇总
  7. bcc校验位怎么算的_数据BCC校验码计算工具
  8. 《逻辑与计算机设计基础(原书第5版)》——1.4 算术运算
  9. 蒜头君的生日(日期格式)
  10. android怎么实现记住密码功能,Android实现用户登录记住密码功能
  11. 员工工号怎么编码_员工编号管理制度
  12. 壳浏览器 android,QQ浏览器2020安卓版
  13. PHP语言25周年,PHP是世界上最好的语言
  14. blender 命令行渲染
  15. html播放mp4不显示画面,浏览器播放mp4格式视频时只有声音看不到画面的原因及解决方法(精)...
  16. MySQL学习笔记①_案例记录
  17. ecshop mysql 操作_ecshop数据库操作函数
  18. if控制条件——BMI
  19. 双向迭代器实现对该商品名称数组的双向(向前和向后)遍历。
  20. 秦曾昌人工智能课程---7、决策树集成学习Tree Ensembles

热门文章

  1. Cracking the coding interview--Q1.7
  2. hadoop配置文件说明
  3. [实战虚拟化]无需借助虚机安装,就能从VHD原生启动
  4. photoshop ps 拉长裙子 方法
  5. golang 数据库null值错误 解决方法
  6. linux shell 字符串查找
  7. golang install/build 生成的文件命名和路径
  8. gif 分支的新建与合并
  9. udp tcp ip 校验和对比
  10. linux 64平台上编译32位程序: GCC编译选项 -m64 -m32 -mx32