SpringBoot-@Transactional注解失效

news/2024/9/25 17:17:38/

@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/news/1450885.html

相关文章

Python爬虫--爬取糗事百科段子

爬取糗事百科段子&#xff1a; 段子在 <div class"content"> 里面的 <span> 标签里面 不过这里有个坑&#xff0c;div 标签跟 span 标签 之间有很多空行 普通 .*? 是匹配不了的&#xff0c;需要使用模式修饰符 S S 的意思 让 .(点) 匹配&#xff0c…

快速确定网络号的范围

目录 方法 下列IP地址中属于网络号的是(C) 十进制转换二进制 二进制转换十进制 计算IP地址中的网络号最直接和简单的方法是使用子网掩码来“屏蔽”掉IP地址中的主机号部分&#xff0c;从而直接得到网络号。这种方法不需要进行复杂的二进制转换和按位与运算&#xff0c;而是…

能源系统-有功无功科普

正向有功总电能表示用户使用电能进行有用功率&#xff08;比如照明、电热器等&#xff09;的总量&#xff0c;而正向无功总电能表示用户使用电能进行无用功率&#xff08;比如电动机、变压器等产生的无功功率&#xff09;的总量。 举个例子来说&#xff0c;正向有功总电能就好…

unittest_parameterized批量测试测试用例

import unittest from parameterized import parameterizeddef add(x, y):return xy"""问题&#xff1a;如果有三组数据需要测试&#xff1f;[(1,1,2), (1,2,3), (0,3,3)] """def get_data():return [(1, 2, 3), (3, 0, 3), (2, 1, 3)]# 定义测试…

CogAgent:开创性的VLM在GUI理解和自动化任务中的突破

尽管LLMs如ChatGPT在撰写电子邮件等任务上能够提供帮助&#xff0c;它们在理解和与GUIs交互方面存在挑战&#xff0c;这限制了它们在提高自动化水平方面的潜力。数字世界中的自主代理是许多现代人梦寐以求的理想助手。这些代理能够根据用户输入的任务描述自动完成如在线预订票务…

【C语言的完结】:最后的测试题

看到这句话的时候证明&#xff1a; 此刻你我都在努力~ 个人主页&#xff1a; Gu Gu Study ​​ 专栏&#xff1a;语言的起点-----C语言 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹…

python使用opencv对图像的基本操作(2)

13.对多个像素点进行操作&#xff0c;使用数组切片方式访问 img[i,:] img[j,:] #将第j行的数值赋值给第i行 img[-2,:]或img[-2] #倒数第二行 img[:,-1] #最后一列 img[50:100,50:100] #50-100行&#xff0c;50-100列&#xff08;不包括第100行和第100列&#xff09; img[:100…

使用Gradio搭建聊天UI实现质谱AI智能问答

使用Gradio搭建聊天UI实现质谱AI智能问答 一、调用智谱 AI API二、使用Gradio搭建聊天UI三、将流式处理添加到交互式聊天机器人 一、调用智谱 AI API 1、获取api_key 智谱AI开放平台网址&#xff1a; https://open.bigmodel.cn/overview 2、安装库pip install zhipuai 3、执…