@Transaction注解失效的几种场景(附有示例代码)

2024-02-06 23:28

本文主要是介绍@Transaction注解失效的几种场景(附有示例代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

0 说明

一、抛出检查异常导致事务不能正确回滚

二、业务方法内自己 try-catch 异常导致事务不能正确回滚

三、AOP 切面顺序导致导致事务不能正确回滚

四、非 public 方法导致的事务失效

五、父子容器导致的事务失效

六、调用本类方法导致传播行为失效

七、@Transactional注解没有保证原子行为

八、@Transactional 方法导致的 synchronized 失效


0 说明

当使用 @Transactional 注解时,可能会出现失效的情况。这种失效可能由于各种因素造成,比如异常处理、AOP切面的顺序、方法的可见性等。失效可能会导致事务无法正确地回滚或提交,从而影响数据的一致性和完整性。以下是八种常见的@Transaction注解失效的场景。

一、抛出检查异常导致事务不能正确回滚

当一个受 @Transactional 注解管理的方法中抛出了检查异常(即继承自 Exception,而非 RuntimeException),Spring 会默认将其视为受检查异常,并不会触发事务的回滚。因此,若想确保事务正确回滚,应当将异常转换为运行时异常。

@Service
public class ExampleService {@Autowiredprivate ExampleRepository repository;@Transactionalpublic void updateData() {try {repository.update(); // 抛出检查异常} catch (SQLException ex) {throw new RuntimeException(ex); // 转换为运行时异常}}
}

二、业务方法内自己 try-catch 异常导致事务不能正确回滚

如果在事务方法内部捕获了异常并进行了处理,而没有将其重新抛出或者抛出非 RuntimeException,则事务不会被回滚。

@Service
public class ExampleService {@Autowiredprivate ExampleRepository repository;@Transactionalpublic void processData() {try {// 业务逻辑} catch (Exception ex) {// 异常处理,但未重新抛出}}
}

三、AOP 切面顺序导致导致事务不能正确回滚

如果在事务方法中使用了 AOP 切面,并且切面的顺序不正确,可能会导致事务失效。通常情况下,应确保事务切面的顺序在其他切面之前。

@Aspect
@Component
public class ExampleAspect {@Around("execution(* com.example.service.ExampleService.*(..))")public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {// 前置逻辑Object result = joinPoint.proceed(); // 调用目标方法// 后置逻辑return result;}
}

四、非 public 方法导致的事务失效

Spring 的事务代理是通过代理对象来实现的,因此 @Transactional 注解只对公有方法有效。非公有方法如果被其他方法内部调用,则事务不会被切面代理管理,导致失效。

@Service
public class ExampleService {@Transactionalpublic void publicMethod() {// 业务逻辑}@Transactionalprivate void privateMethod() {// 业务逻辑}public void callerMethod() {privateMethod(); // 被调用的非公有方法内的事务失效}
}

五、父子容器导致的事务失效

在 Spring 中,如果父子容器的配置不正确,可能会导致事务失效。一种常见情况是父容器和子容器分别管理了事务,但子容器中的事务不会受父容器的影响,导致事务操作失效。

@Configuration
@EnableTransactionManagement
public class ParentConfig {@Beanpublic DataSource dataSource() {// 配置数据源}@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dataSource());}
}@Configuration
@EnableTransactionManagement
public class ChildConfig {@Beanpublic DataSource dataSource() {// 配置不同的数据源}@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dataSource());}
}

六、调用本类方法导致传播行为失效

如果在同一个类中调用带有 @Transactional 注解的方法,Spring 的事务传播行为可能会失效。因为 Spring 通过 AOP 代理来管理事务,同一个类内的方法调用并不会触发代理,事务传播行为不会被应用。

@Service
public class ExampleService {@Transactionalpublic void methodA() {methodB(); // 调用本类方法}@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {// 事务传播行为 REQUIRES_NEW 失效}
}

七、@Transactional注解没有保证原子行为

虽然 @Transactional 注解可以确保一组操作要么全部成功,要么全部失败,但它并不能保证原子性操作。如果在一个事务方法中出现多个数据库操作,并且某些操作成功,而其他操作失败,那么只有失败的那部分会回滚,而成功的部分会保留,这可能导致数据不一致。

@Service
public class ExampleService {@Autowiredprivate ExampleRepository repository;@Transactionalpublic void updateData() {repository.updateData1(); // 更新操作1repository.updateData2(); // 更新操作2// 操作2失败,但操作1已提交,数据不一致}
}

八、@Transactional 方法导致的 synchronized 失效

如果一个方法同时使用了 @Transactional 和 synchronized 注解,那么 synchronized 的锁将被事务代理所绕过,导致锁的失效,多个线程可能同时访问该方法,破坏了同步性。

@Service
public class ExampleService {@Transactionalpublic synchronized void process() {// 事务方法}
}

在上述代码中,尽管 process 方法被声明为 synchronized,但由于被 @Transactional 注解修饰,Spring 的事务代理会绕过 synchronized 锁,导致同步失效。

这篇关于@Transaction注解失效的几种场景(附有示例代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/685868

相关文章

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

sky-take-out项目中Redis的使用示例详解

《sky-take-out项目中Redis的使用示例详解》SpringCache是Spring的缓存抽象层,通过注解简化缓存管理,支持Redis等提供者,适用于方法结果缓存、更新和删除操作,但无法实现... 目录Spring Cache主要特性核心注解1.@Cacheable2.@CachePut3.@Ca

QT Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

MySQL中On duplicate key update的实现示例

《MySQL中Onduplicatekeyupdate的实现示例》ONDUPLICATEKEYUPDATE是一种MySQL的语法,它在插入新数据时,如果遇到唯一键冲突,则会执行更新操作,而不是抛... 目录1/ ON DUPLICATE KEY UPDATE的简介2/ ON DUPLICATE KEY UP