发现Spring事务的一个实锤bug,官方还拒不承认?你来评评理... (中)

简介: 发现Spring事务的一个实锤bug,官方还拒不承认?你来评评理... (中)

大幕拉开


image.png

image.png

image.png

接下来,神奇的事情就要发生了,铁子。

com.example.transactional.exception.AgeExceptionOver18

com.example.transactional.exception.AgeException

虽然这是两个不同的异常,但是这两个字符串进行 contains 操作,你说是不是返回 true?

image.png

image.png

image.png

image.png

image.png

但是,如果下面这两个字符串进行 equals 操作,你说是不是返回 false,问题就得到解决了?

com.example.transactional.exception.AgeExceptionOver18

com.example.transactional.exception.AgeException

道理是这么个道理,但是我觉得问题肯定没这么简单。

首先我觉得这里用 contains 肯定是故意的,但是具体出于什么目的,我还真不确定。

于是和我讨论的读者提出一个看法,会不会是为了满足 rollbackForClassName 这个属性:

image.png

在正常使用的场景下,我们是可以完成回滚操作的。

对应地方的代码的值是这样的;

image.png

java.lang.NullPointerException 字符串当然包含了 NullPointerException 字符串。所以我们进行回滚嘛。没毛病。

但是如果我们用 equals 操作,那么就匹配不上,导致 rollbackForClassName 属性失效了。

所以把 contains 修改为 equals 属于拆西墙,补东墙的措施,不可取。

但是 rollbackForClassName 属性在我们的 Demo 下,也是没有效果的。

比如我把程序改成这样,你说,是不是就乱套了?

image.png

同样的道理嘛。

com.example.transactional.exception.AgeExceptionOver18 字符串当然包含了 AgeException 字符串了。

但是我并不想回滚啊,哥,你好好看看,我抛出来的异常是 AgeExceptionOver18 呀。

到这里,我想问题我应该已经描述的非常清楚了,要是你还是没明白问题是什么,那你不用往下看了,再看一下“大幕拉开”这一节。

不然后面你很难入戏。

image.png

铺垫一波


为了把真正的问题更好的抛出来,我必须得先把另外一个相关的问题引出来,作为铺垫。

首先,我们去 Spring 项目的 issues 里面搜一下 getDepth 方法所在的 RollbackRuleAttribute 这个类。

看看有没有相关的蛛丝马迹,结果如下:

image.png

经过分析,对我有帮助的也只有第一条内容。

https://github.com/spring-projects/spring-framework/pull/24682

题目叫做:

Improve javadoc in RollbackRuleAttribute regarding nested classes。

改进 RollbackRuleAttribute 中关于嵌套类的 javadoc。

从题目我们知道这是一次对于文档的改进。

那么具体是啥改进呢?

image.png

可以看到他的描述中也提到了我们前面分析的那一个“万恶之源”的方法。

关于他具体说了什么,其实我也不用给你翻译,直接给你看他提交的代码就一目了然了:

image.png

他主要说个了内部类的问题,而且他这个问题和我们的还有点不一样。

他的两个异常类,一个叫 EnclosingException,另一个叫做 EnclosedException,这两个字符串是不存在 contains 关系的。

那么在内部类的场景下,问题是什么呢?

我也给你演示一个,你只需要看一眼就明白了,示例代码如下:

image.png

需要注意的是,我现在的两个异常是 AgeException 和 AgeOver18Exception,这二者并不存在包含关系。

前面做 Demo 的时候是 AgeExceptionOver18。

AgeOver18Exception

AgeExceptionOver18

别看花眼了。

你看,内部类的时候抛出异常是这样的:

throw new AgeException.AgeOver18Exception();

你要是没回过味儿来,没关系,断点一打,代码一跑就恍然大悟:

image.png

看明白没,铁子。内部类抛出的异常的全路径名称是这样的:

xxx.UserInfoService\$ AgeException$AgeOver18Exception

这不就包含 AgeException 了吗,不就匹配上了吗,不就回滚了吗?

所以,虽然他这个问题的触发方式和我前面提到的还不一样,但是“万恶之源”是一样的。

那么解决方案是什么呢?

仅仅是修改了一下文档,从文档的角度表明了这个情况是会被回滚的:


image.png

对应到源码,也就是这个地方的注释:

org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(java.lang.Class<?>)

image.png


好,我们现在冷静的思考一下,这里仅仅是从文档的角度来修复这个问题,在文档里面明确说明指定异常的内部类也会被回滚,这个做法对不对?

我认为勉强是可以接受的。

比如,我们知道某个异常类被标记为应该被回滚,那么这个异常类的子类应该被回滚,这是没问题的。

我认为内部类和子类应该保存同样的逻辑,毕竟它们之前确实存在代码上的关联关系,从这个角度上也说的过去。

毕竟一切解释权归官方所有嘛。

到这里你要记住:

  • RollbackRuleAttribute 类已经因为在回滚异常的判断上使用 contains 爆出过内部类的问题。
  • 这个问题通过修改 javadoc 描述的方式进行了修复,没有修改任何代码。
  • 这个解决方案勉强说的过去。

好了,铺垫完成了。

目录
相关文章
|
3月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
9月前
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
4月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
9月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
244 0
|
9月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
1195 0
|
9月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
251 0
|
7月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
428 10
|
6月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
494 1
|
9月前
|
SQL Java 数据库连接
Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的 2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean 3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解 4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接 5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步 6. 然后执⾏当前⽅法,⽅法中会执⾏sql 7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务 8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务
|
9月前
|
JavaScript Java 开发者
Spring事务失效,常见的情况有哪些?
本文总结了Spring事务失效的7种常见情况,包括未启用事务管理功能、方法非public类型、数据源未配置事务管理器、自身调用问题、异常类型错误、异常被吞以及业务和事务代码不在同一线程中。同时提供了两种快速定位事务相关Bug的方法:通过查看日志(设置为debug模式)或调试代码(在TransactionInterceptor的invoke方法中设置断点)。文章帮助开发者更好地理解和解决Spring事务中的问题。
379 7