SpringBoot-@Transactional注解失效

devtools/2024/10/22 5:27:52/

@Transactional注解失效

@Transactional失效场景

以下是一些常见导致@Transactional注解失效的场景,配合相应的Java代码演示:

1、方法修饰符非公开(非public

@Transactional注解失效的原因在于Spring事务管理器如何实现对事务的代理和管理。Spring使用AOP(面向切面编程)机制来处理@Transactional注解的方法。具体而言,Spring会在运行时为带有@Transactional注解的Bean创建一个代理对象,代理对象负责在方法调用前后添加事务的开始、提交或回滚等逻辑。

当方法修饰符为非公开(非public)时,导致@Transactional失效的原因主要有以下两点:

  1. AOP代理的默认行为
    Spring AOP默认仅对public方法进行代理增强。这是因为Spring使用JDK动态代理(对于接口代理)或CGLIB代理(对于类代理)来创建代理对象。这两种代理方式均基于继承或接口实现,对非public方法的代理存在技术上的限制。JDK动态代理只能代理接口方法,自然无法代理非public方法;CGLIB虽然可以代理类的非public方法,但Spring AOP的默认配置并不包括对非public方法的增强。

  2. 设计原则与最佳实践
    从设计原则和最佳实践的角度考虑,服务层方法通常应该对外提供明确的、有限的接口(即public方法),而将内部细节(如非public方法)隐藏起来。因此,@Transactional注解通常应用于服务层的业务方法,这些方法通常是public的,以便外部调用。非public方法通常用于实现具体的业务逻辑,如果它们需要参与到事务管理中,通常是因为它们被某个@Transactional注解的public方法调用,此时事务管理应由调用方(即public方法)负责。

综上所述,由于Spring AOP的默认行为和设计原则的考量,非public方法上的@Transactional注解通常不会被Spring事务管理器识别和处理,从而导致事务注解失效。若确实需要对非public方法进行事务管理,通常需要调整Spring的AOP配置,或者更改为在调用这些方法的public方法上添加@Transactional注解。然而,这并不符合最佳实践,通常建议将事务边界设定在对外提供的public方法上。
在这里插入图片描述

2、内部方法调用

@Service
public class UserService {@Transactionalpublic void updateUser() {// 调用内部私有方法,事务不会传播到此方法processUpdate();}// @Transactional在此处无效,因为是通过非代理对象直接调用private void processUpdate() {// 更新数据库操作...}
}
  1. 异常捕获但未抛出

    @Service
    public class OrderService {@Transactionalpublic void placeOrder() {try {// 执行可能抛出异常的操作saveOrderDetails();// 其他业务逻辑...} catch (Exception e) {// 异常被捕获但未重新抛出,事务不会回滚log.error("An error occurred while placing the order", e);}}private void saveOrderDetails() throws SQLException {// 可能抛出SQLException的数据库操作}
    }
    
  2. 事务传播设置不当

    @Service
    public class TransactionalServiceA {@Transactional(propagation = Propagation.NEVER)public void nonTransactionalMethod() {// 如果此方法在另一个已开启事务的方法中被调用,由于传播设置为NEVER,此处事务将不会生效performTransactionalOperation();}@Transactionalprivate void performTransactionalOperation() {// 应该在事务中执行的操作}
    }
    
  3. 配置问题:未启用代理模式或代理对象未被正确使用

    // 假设配置中未启用Spring AOP代理(如使用了CGLIB代理而非JDK动态代理)
    // 或者在某些情况下直接通过new关键字创建了Service实例,而非依赖注入
    UserService userService = new UserService();// 由于userService不是由Spring容器管理的代理对象,@Transactional将失效
    userService.updateDataInTransaction();
    
  4. 事务超时或并发控制设置冲突

    @Service
    public class InventoryService {@Transactional(timeout = 1)  // 设置较短的事务超时时间public void adjustStock() {// 长时间运行的数据库操作,可能导致事务超时而提前结束,不保证原子性// ...}
    }
    

以上代码示例展示了可能导致@Transactional注解失效的几种常见场景。在实际使用中,应确保正确配置Spring事务管理器、合理设置事务属性,并遵循Spring AOP代理的使用规则,以确保事务功能正常运作。


http://www.ppmy.cn/devtools/30650.html

相关文章

springboot2.6.7集成springfox3.0.0

springboot2.6.7集成springfox3.0.0 1. pom配置2. 增加swagger自动配置类3. 配置修改4. 自动配置类增加以下内容参考 1. pom配置 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --> <dependency><groupId>io.springfox</g…

机器学习入门之非监督学习和半监督学习

文章目录 非监督学习半监督学习机器学习的核心价值 非监督学习 与监督学习相反&#xff0c;非监督学习的训练数据集是完全没有标签的数据&#xff0c;他本质上所做的工作都是聚类的 给定数据之后&#xff0c;聚类能从中学习到什么&#xff0c;就完全取决于数据本身的特性的&a…

上海计算机学会2022年4月月赛C++丙组T3平衡括号(简)

题目描述 给定一个只包含 ( 与 ) 的括号序列&#xff0c;请删除尽量少的括号&#xff0c;使它变成平衡的。平衡的定义如下&#xff1a; 空序列是平衡的&#xff1b;如果某个括号序列 s 是平衡的&#xff0c;那么 (s) 也是平衡的&#xff1b;如果某两个括号序列 s 与 t 都是平…

【机器学习】机器学习学习笔记 - 监督学习 - KNN线性回归岭回归 - 02

监督学习 KNN (k-nearest neighbors) KNN 是用 k 个最近邻的训练数据集来寻找未知对象分类的一种算法 from sklearn import neighbors# 分类 # 创建KNN分类器模型并进行训练 classifier neighbors.KNeighborsClassifier(num_neighbors, weightsdistance) classifier.fit(X,…

处理分支更新与pull操作

处理分支更新与pull操作 问题描述 There is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details.git pull <remote> <branch> If you wish to set tracking information for th…

【免费AI系统】智狐AIs:企业级AI解决方案,提升您的工作效率

今天&#xff0c;我将为您介绍一个创新的AI平台——智狐AIs&#xff0c;这是一个致力于让AI技术变得易于接触和使用的平台&#xff0c;它为不同层次的用户提供了一个功能强大且易于操作的交互环境。 智狐AIs&#xff1a;您智能生活的新伙伴 智狐AIs以其简洁而强大的设计&#…

wpf 树形结构

Simplifying the WPF TreeView by Using the ViewModel Pattern - CodeProject 【原创】WPF TreeView带连接线样式的优化&#xff08;WinFrom风格&#xff09; - iDream2016 - 博客园 (cnblogs.com)

顺序表经典算法

顺序表经典算法 1.移除元素 题目&#xff1a; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的…