- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
emm,又又又踩坑啦。这次的需求主要是对逾期计算的需求任务进行优化,现有的计算任务运行时间太长了。简单描述下此次的问题: 在项目中进行多个数据库执行操作时,我们期望的是将其整个封装成一个事务,要么全部成功,或者全部失败,然而在自测异常场景时发现,里面涉及的第一个数据状态更新成功了,但是后面的数据在插入出现异常,后面查询数据表发现,该数据的状态已经被更新成功啦 .
emmm,查看代码发现确实是使用了@Transactional注解没问啊。于是通过查询网上相关资料发现,在使用Spring中事务注解@Transactional时会存在几种场景下该注解失效,即不能按照预期封装成一个事务操作,于是对该注解进行学习并对相关失效场景进行分析,整理文章如下; 。
属性 | 类型 | 描述 |
---|---|---|
value | String | 可选的限定描述符,指定使用的事务管理器 |
propagation | Enum:Propagation· | 可选的事务传播行为设置 |
isolation | Enum:Isolation | 可选的事务隔离级别设置 |
readOnly | boolean | 读写或只读事务,默认读写 |
timeout | int | 事务超时时间设置 |
rollbackFor | Class对象数组,必须继承自Throwable | 导致事务回滚的异常类数组 |
rollbackForClassName | 类名数组,必须继承自Throwable | 导致事务回滚的异常类名字数组 |
noRollbackFor | Class对象数组,必须继承自Throwable | 不会导致事务回滚的异常类数组 |
noRollbackForClassName | 类名数组,必须继承自Throwable | 不会导致事务回滚的异常类名字数组 |
propagation代表事务的传播行为,默认值为 Propagation.REQUIRED 。
属性 | 描述 |
---|---|
Propagation.REQUIRED | 若当前存在事务则加入该事务,若不存在则创建一个新事务(默认) |
Propagation.SUPPORTS | 若当前存在事务则加入该事务,若不存在则以非事务的方式继续进行 |
Propagation.MANDATORY | 若当前存在事务则加入该事务,若不存在则抛出异常 |
Propagation.REQUIRES_NEW | 重新创建一个新的事务,若当前存在事务则暂定当前事务 |
Propagation.NOT_SUPPORTED | 以非事务的方式运行,若当前存在事务则暂定当前事务 |
Propagation.NEVER | 以非事务的方式运行,若当前存在事务则抛出异常 |
Propagation.NESTED | 与Propagation.REQUIRED效果一样 |
@Transactional注解可以作用在接口、类、类方法中.
当作用于类时 ,表示所有该类的public方法都配置相同的事务属性信息.
当作用于方法时 ,当类配置了@Transactional注解,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息.
当作用于接口时 ,不推荐使用,因为在接口使用@Transactional并且配置了Spring AOP使用CGLib动态代理将会导致其失效.
失效原因:在Spring AOP代理时, TransactionInterceptor (事务拦截器)在目标方法执行 前后 进行拦截, DynamicAdvisedInterceptor (CglibAopProxy的内部类)的 Intercept 方法或 JDKDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransationAttributeSource 的 computeTransactionAttribute 方法,获取@Transactional注解的事务配置信息.
1 protected TransactionAttribute computeTransactionAttribute(Method method,
2 Class<?> targetClass) {
3 // Don't allow no-public methods as required.
4 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
5 return null;
6 }
此方法会检查目标方法的修饰符 是否为public ,非public作用域则 不会获取 @transactional的属性配置信息。其中 protected、private 修饰的方法上使用 @Transactional 注解,事务会 失效 但不会有任何报错.
失效原因:配置错误, PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER三种事务传播方式不会发生回滚.
▪ 实例验证:写了一个demo进行测试。demo主要功能如下:执行两次数据库插入操作,并在扩展信息字段中添加备注; 。
▪ 运行结果如下,构造的单号不存在订单查询为空触发异常,观察数据库发现,第一次数据库插入操作已经 执行成功 ,故而验证@Transactional注解 失效 ; 。
rollbackFor可以指定能够触发事务回滚的异常类型。Spring默认抛出了unchecked异常(继承自RuntimeException)或者Error才会回滚事务。若事务中抛出了其他类型的异常,但却期望Spring能够回滚事务,就需要指定rollbackFor属性,否则就会失效.
比如类demo中有方法A和B,方法B中使用@Transactional注解,方法A没有注解,但是demo类通过方法A调用方法B,像这种间接调用会导致方法B中的@Transactional事务注解失效.
失效原因 :只有当事务方法被当前类以外的代码调用时,才会有Spring生成的代理对象管理。(Spring AOP代理机制造成的).
▪ 实例验证 :demo中构造场景为在同一个类中,在test方法中添加@Transactional注解,querRiskScore方法中不添加该注解,然后在querRiskScore方法中调用test方法;观察下多个插入操作是否会因为异常而中断回滚; 。
▪ 运行结果如下,还是通过构造的单号不存在订单查询为空触发异常,观察数据库发现,第一次数据库插入操作已经 执行成功 , 第二次 数据插入 操作失败 ,并没有因为异常而触发事务操作,故而验证@Transactional注解方法间的调用会 失效 ; 。
失效原因 :线程不属于Spring托管,故线程不能够默认使用Spring的事务,也不能获取Spring注入的bean,在被Spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制.
比如B方法内部抛了异常,而A方法此时try-catch了B方法的异常,则该事务不能正常回滚.
失效原因 :因为B方法中抛出异常以后,标识当前事务需要rollback,但是A方法中由于你手动的捕获这个异常并进行处理,A方法认为当前事务应该正常commit,此时就出现前后不一致,会抛出 org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only 异常.
▪ 实例验证 :这个场景的本质还是异常被捕获导致无法正常的抛出,进而导致@Transactional注解无法正常工作,我简化了下demo实例场景,构造场景如下:在querRiskScore方法中添加@Transactional注解,然后在querRiskScore方法中对异常进行捕获;观察下多个插入操作是否会因为异常而中断回滚; 。
▪ 运行结果如下,还是通过构造的单号不存在订单查询为空触发异常,但是我们在方法内部对该异常进行捕获,并未向上层抛出,我们期望的场景是两次数据插入执行失败,但是观察数据库发现,第一次数据库插入操作已经 执行成功 , 第二次 数据插入 执行成功 ,与我们的预期结果不符,故而验证@Transactional注解在 方法中异常被捕获的场景中 会 失效 ; 。
究其原因 :Spring的事务是在调用业务方法之前开始的,业务方法执行完毕之后才执行commit 或 rollback,事务是否执行取决于是否抛出runtime异常,如果抛出runtime exception并在你的业务方法中并没有catch到的话,事务就会回滚.
事务(Transaction)是由一系列对系统中数据进行访问与更新的操作组成的一个程序执行逻辑单元(Unit).
通常我们所指的事务是指数据库事务,使用数据库事务有以下两处优点:
当多个应用程序并发访问数据库时,事务可以在这些应用程序之间提供一个隔离方法,以 防止彼此的操作互相干扰 .
事务为数据库操作序列提供了一个从失败恢复到正常状态的方法,同时提供了数据库即使在 异常状态 下仍能 保持数据一致性 的方法.
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性,简称事务的ACID特性.
事务的原子性是指事务必须是一个原子的操作序列单元,即事务中包含的各项操作在一次执行过程中只会出现两种状态:全部成功执行、全部不执行。任何一项操作失败都将导致整个事务失败,同时其他已经被执行的操作都将被撤销并回滚,只打所有的操作全部成功,整个事务才算是成功完成.
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。也就是说,事务执行的结果必须是使数据库从一个一致性状态转变到另一个一致性状态,因此当数据库只包含成功事务提交 的结果时,就能说数据库处于一致性状态。而如果数据库系统在运行过程中发生故障, 有些事务尚未完成就被迫中断,这些未完成的事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态.
事务的隔离性是指在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。也就是说,不同的事务并发操纵相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的 各个事务之间不能互相干扰.
事务一旦提交,其所做的修改就会永久保存到数据库中,即使数据库发生故障也不应该对其有任何影响。需要注意的是,事务的持久性不能做到100%的持久,只能从事务本身的角度来保证永久性,而一些外部原因导致数据库发生故障,如硬盘损坏,那么所有提交的数据可能都会丢失.
Spring中同样提供了很好的事务管理机制,主要分为 编程式事务 和 声明式事务 .
是指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较强。编程式事务方式需要开发者在代码中手动的管理事务的开启、提交、回滚等操作.
public void test() {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 事务操作
// 事务提交
transactionManager.commit(status);
} catch (DataAccessException e) {
// 事务提交
transactionManager.rollback(status);
throw e;
}
}
声明式事务是基于AOP面向切面,它将具体业务和事务处理部分解耦,代码侵入性很低,实际开发中比较常用。我们常用TX和AOP的xml配置文件方式和@Transactional注解方式.
▪声明式事务的优点:
对代码无侵入性,方法内只需要写业务逻辑,节省很多代码量.
▪声明式事务的缺点:
1、声明式事务粒度问题:声明式事务的 局限 就是 最小粒度要作用在方法上 ,且不适合 耗时长 、 高并发 场景.
2、声明式事务容易被开发者忽略,当事务嵌套的方法中存在RPC远程调用、MQ发送、Redis更行、文件写入等操作可能存在以下场景:
▪ 事务嵌套的方法中RPC调用成功了,但是本地事务回滚导致RPC调用无法回滚(暂不讨论分布式事务).
▪事务嵌套的方法中远程调用会拉长整个事务周期,导致事务的数据库连接一致被占用,类似操作过多会导致数据库连接池耗尽.
3、声明式事务使用错误会导致在某些场景下 失效 .
作者:京东科技 宋慧超 。
来源:京东云开发者社区 。
最后此篇关于聊聊Spring注解@Transactional失效的那些事的文章就讲到这里了,如果你想了解更多关于聊聊Spring注解@Transactional失效的那些事的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
注解@CrossOrigin 出于安全原因,浏览器禁止Ajax调用驻留在当前原点之外的资源。例如,当你在一个标签中检查你的银行账户时,你可以在另一个选项卡上拥有EVILL网站。来自EVILL的脚本
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界. 这篇CFSDN的博客文章深入理解Java高级特性——注解由作者收集整理,如果你对这篇文章有兴趣,
概述 在这个快速教程中,我们将探索 Spring 的 @RequestParam 注解。 简单地说,我们可以使用 @RequestParam 从请求中提取查询参数、表单参数甚至文件。我们将讨论如何使用
我有一个关于 Spring @Async 注释的问题。我有一个 Controller 自动连接了一个服务(GnInsuranceDetailsService) @RequestMapping(va
我在使用注释来调用注释所属的方法时遇到了一些麻烦......我将举一个例子: class MyEventHandlers { @handler(id=“1”) public doSom
我是.Net程序员,但是这次我正在从事Java项目,并且遇到了一些困难。这个 java 项目不是我的,它是由其他开发人员开发的,并且使用 Hibernate。 当我运行 Ant 构建器时,我收到此错误
我在 Grails 文档(第 9 章:测试)中读到过这个注解。但是我不明白这是什么... 问题是我需要模拟 GORM 的动态方法,有一种方法可以自动模拟它们,而不必编写我需要的所有方法吗? 最佳答案
这个问题在这里已经有了答案: How to get annotation class name, attribute values using reflection (2 个答案) 关闭 5 年前。
如何了解 Java EE 6 JMS 注释规范支持的所有有效属性集@ActivationConfigProperty Java EE 6 Documentation for @ActivationCo
我认为这是不可能的,但也许我错了。所以我问你,如果可能的话。 ;-) 如果我定义了一个注释,它只接受类引用,它扩展了一些可能的接口(interface)或类: Class serviceIFProv
我正在尝试使用 javax.validation 验证一些 DTO,但似乎注释 @NotEmpty 没有检查参数是否为 null。 这是我的类(class): Person.class public
我是 hibernate 新手,我正在尝试学习它,但在尝试使一对多关系正常工作时遇到了问题。我尝试了几个例子,但似乎没有一个起作用。 有人可以看一下下面的代码并告诉我哪里出了问题吗?我尝试了很多不同的
这个问题已经有答案了: Why doesn't Java offer operator overloading? (17 个回答) 已关闭 9 年前。 每个人都知道 Java 中的简单算术如何用于基元
有人知道如何用 Python 处理这种 XML 注释,这是我第一次看到。 <?link id="752760" resource-uuid="UUID-9f0575a3-1847-1cde-fd
我遇到了这个link这解释了如何继承 bean。假设此示例中的 HelloWorld 类使用 @Component 注释作为 bean 公开,如何创建另一个继承此 bean 的 bean?我可以使用
谁能告诉我这段代码是否: public class OvTester { @Override public int hashCode() { return toStri
我有一个实体,它有一个非键列,我已将其设置为在我的数据库中自动生成。 我不能使用 @GeneratedValue,因为据我所知,它仅适用于关键字段。 在这种情况下,如何指示非键列是自动生成的? 最佳答
所以可能像很多人一样,我通常会临时注释掉代码,主要是为了调试目的。我目前放了类似 **DEBUG** 或任何容易搜索的内容,但我认为让编译器在发现临时注释掉的代码时输出警告(甚至错误)可能很有用。我想
此组件解决的问题是: 「谁」在「什么时间」对「什么」做了「什么事」 本组件目前针对 Spring-boot 做了 Autoconfig,如果是 SpringMVC,也可自己在 xml 初始化 b
配置全局乱码过滤器 参数绑定注解@RequestParam 注解@RequestParam的参数使用说明 获得Restful风格的参数 自定义类型转换器 自定义转换器的开发步骤: 获得Servlet相
我是一名优秀的程序员,十分优秀!