当前位置: 首页 > news >正文

Spring事务失效场景?

题目详细答案

Spring事务失效的场景主要有以下几种。

非public方法使用@Transactional

场景描述:Spring事务管理是基于AOP实现的,而AOP对于JDK动态代理CGLib动态代理只会代理public方法。如果事务方法的访问修饰符为非public,SpringAOP无法正确地代理该方法,从而导致事务失效。

示例代码:事务方法的访问修饰符被设置为private、default或protected。

解决方案:将需要事务管理的方法设置为public。

在同类中的非事务方法调用事务方法

场景描述:Spring的事务管理是通过动态代理实现的,只有通过代理对象调用的方法才能享受到Spring的事务管理。如果在同一个类中,一个没有标记为@Transactional的方法内部调用了一个标记为@Transactional的方法,那么事务是不会起作用的。

解决方案:尽量将事务方法放在不同的类中,或者使用Spring的AopContext.currentProxy()来获取当前类的代理对象,然后通过代理对象调用事务方法。

事务传播级别属性设置不当

场景描述:在Spring的事务管理中,如果在一个支持当前事务的方法(比如,已经被标记为@Transactional的方法)中调用了一个需要新事务的方法,如果后者方法抛出了异常,但异常并未被Spring识别为需要回滚事务的异常,那么后者的事务将不会回滚。

异常类型不匹配

场景描述:默认情况下,Spring只有在方法抛出运行时异常或者错误时才会回滚事务。对于检查性异常,即使你在方法中抛出了,Spring也不会回滚事务,除非你在@Transactional注解中显式地指定需要回滚哪些检查性异常。

解决方案:了解Spring事务管理对异常的处理,必要时在@Transactional注解中指定需要回滚的异常类型。

事务拦截器配置错误

场景描述:如果没有正确地配置事务拦截器,例如没有指定切入点或指定了错误的切入点,就会导致Spring事务失效。

@EnableTransactionManagement
@Configuration
public class TxConfig {@Beanpublic Advisor transactionAdvisor() {AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression("execution(* com..service.*.*(..))"); // 包路径错误return new DefaultPointcutAdvisor(pointcut, transactionInterceptor());}
}

事务超时配置错误

场景描述:如果事务超时时间设置得太短,就有可能在事务执行过程中出现超时,从而导致Spring事务失效。

Spring事务超时是通过JDBC的java.sql.Connection#setNetworkTimeout()实现的,底层流程:

if (System.currentTimeMillis() - startTime > timeoutMillis) {throw new TransactionTimedOutException("Transaction timed out");
}

Spring事务失效场景深度解析

一、非public方法失效的本质原因

底层机制

  1. 代理生成限制
// Spring源码中的判断逻辑
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null; // 直接返回不创建事务属性
}
    • JDK动态代理只能代理接口中的public方法
    • CGLIB虽然能代理类方法,但Spring主动限制了非public方法的事务支持
  1. 设计考量
    • 非public方法通常被视为内部实现细节
    • 保持事务边界清晰(public方法才是服务契约)

典型错误示例

@Service
public class PaymentService {@Transactionalprotected void processPayment() {  // protected方法// 事务不会生效!}
}

二、同类调用失效的代理机制

核心问题图解

[客户端] --> [Spring代理对象] --> [真实对象]调用createOrder()       this.validate()绕过代理

字节码层面分析

  1. 代理对象生成后,方法调用流程:
    • 外部调用:proxy.createOrder()
    • 内部调用:realObject.validate()(直接调用,不走代理)

解决方案对比

方案

优点

缺点

拆分类

符合单一职责原则

增加类数量

自注入

改动最小

存在循环依赖风险

AopContext.currentProxy()

灵活

需配置exposeProxy=true

三、传播行为配置陷阱

REQUIRES_NEW的隔离性

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditLog() {// 即使外层事务回滚,此操作仍会提交// 但会创建新连接,可能耗尽连接池
}

NESTED的数据库支持

  • 支持:MySQL、PostgreSQL
  • 部分支持:Oracle(行为差异)
  • 不支持:MyISAM引擎

四、异常处理不当的判定逻辑

Spring回滚决策树

  1. 检查rollbackFor/noRollbackFor明确指定的异常
  2. 默认规则:
    • RuntimeException及其子类 → 回滚
    • Error及其子类 → 回滚
    • 检查型异常(Exception) → 提交

易错场景示例

@Transactional
public void importData() throws IOException {try {parseFile(); // 可能抛出IOException} catch (IOException e) {throw new BusinessException(e); // 必须转换为RuntimeException}
}

五、数据库引擎关键影响

事务支持矩阵

引擎特性

InnoDB

MyISAM

Memory

事务支持

✔️

✖️

✖️

行级锁

✔️

✖️

✖️

外键支持

✔️

✖️

✖️

检查方法

SHOW TABLE STATUS WHERE Name='table_name';

六、静态/最终方法限制

JVM方法调用机制

  • final方法:静态绑定,编译期确定调用目标
  • static方法:类级别调用,与对象实例无关
  • 二者都无法被动态代理拦截

事务调试四步法

  1. 检查代理类型
System.out.println(service.getClass().getName());
// 应输出包含$$EnhancerBySpringCGLIB$$或$Proxy的类名
  1. 验证事务状态
TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.getCurrentTransactionName();
  1. 开启事务日志
logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc=DEBUG
  1. 数据库监控
SHOW ENGINE INNODB STATUS;  -- MySQL
SELECT * FROM V$TRANSACTION; -- Oracle

最佳实践清单

  1. 编码规范
    • 所有事务方法必须为public
    • 避免在事务方法中捕获所有异常
    • 显式指定rollbackFor
  1. 配置检查
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class TxConfig {@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dataSource());}
}
  1. 测试验证
@Test
@Transactional
public void testWithRollback() {// 测试后自动回滚assertThrows(Exception.class, () -> service.method());
}

理解这些原理后,可以系统性地避免事务失效问题,而不仅是记住表面现象。实际开发中建议结合日志监控和单元测试,确保事务行为符合预期。

http://www.dtcms.com/a/318959.html

相关文章:

  • 光纤滑环 – 光纤旋转接头(FORJ)- 杭州驰宏科技
  • 科技云报到:热链路革命:阿卡 CRM 的 GTM 定位突围
  • 芯谷科技--高效噪声降低解决方案压缩扩展器D5015
  • 全球化2.0 | 泰国IT服务商携手云轴科技ZStack重塑云租赁新生态
  • 安全守护,温情陪伴 — 智慧养老产品上新
  • Element Plus实现分页查询
  • 码头岸电系统如何保障供电安全?安科瑞绝缘监测及故障定位方案解析
  • Rust爬虫与代理池技术解析
  • NAS技术在县级融媒体中心的架构设计与安全运维浅析
  • VSCode ssh一直在Setting up SSH Host xxx: Copying VS Code Server to host with scp等待
  • 支付宝小程序商城怎么搭?ZKmall开源商城教你借力蚂蚁生态做增长
  • 【Agent】ReAct:最经典的Agent设计框架
  • 【pytorch(06)】全连接神经网络:基本组件认知,线性层、激活函数、损失函数、优化器
  • Django 表单:深度解析与最佳实践
  • 高性能分布式通信框架:eCAL 介绍与应用
  • 解锁高效开发:AWS 前端 Web 与移动应用解决方案详解
  • 区块链技术原理(2) -数据结构
  • 云平台运维工具 ——AWS 原生工具
  • 告别Cursor!最强AI编程辅助Claude Code安装到使用全流程讲解
  • MySQL面试题及详细答案 155道(061-080)
  • 【图文教程】三步用Cpolar+JuiceSSH实现手机远程连接内网Linux虚拟机
  • 平台服务器被入侵,使用WAF能防范吗?
  • 机器学习——04 逻辑回归
  • LoRaWAN的网络拓扑
  • graalvm初探
  • 急危重症专科智能体”构建新一代急诊、手术与重症中心的AI医疗方向探析
  • DBeaver 25.1.0 转储数据库失败解决方案(适配最新版界面)
  • Android Auto开发指南
  • concurrentqueue:一个高并发高性能的C++无锁队列
  • Oracle exp imp expdp impdp 命令详解