@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 security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

Flutter打包APK的几种方式小结

《Flutter打包APK的几种方式小结》Flutter打包不同于RN,Flutter可以在AndroidStudio里编写Flutter代码并最终打包为APK,本篇主要阐述涉及到的几种打包方式,通... 目录前言1. android原生打包APK方式2. Flutter通过原生工程打包方式3. Futte

golang 日志log与logrus示例详解

《golang日志log与logrus示例详解》log是Go语言标准库中一个简单的日志库,本文给大家介绍golang日志log与logrus示例详解,感兴趣的朋友一起看看吧... 目录一、Go 标准库 log 详解1. 功能特点2. 常用函数3. 示例代码4. 优势和局限二、第三方库 logrus 详解1.

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

在C#中调用Python代码的两种实现方式

《在C#中调用Python代码的两种实现方式》:本文主要介绍在C#中调用Python代码的两种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#调用python代码的方式1. 使用 Python.NET2. 使用外部进程调用 Python 脚本总结C#调

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S