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

Java-142 深入浅出 MySQL Spring事务失效的常见场景与解决方案详解(4)

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI篇持续更新中!(长期更新)

AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布!“快的模型 + 深度思考模型 + 实时路由”,持续打造实用AI工具指南!📐🤖

💻 Java篇正式开启!(300篇)

目前2025年10月07日更新到:
Java-141 深入浅出 MySQL Spring事务失效的常见场景与解决方案详解(3)
MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

请添加图片描述

事务失效场景(3)

参考来源

● https://heapdump.cn/article/5542790

续接上节

多线程调用与Spring事务机制详解

Spring事务的基本原理

Spring的事务管理是基于ThreadLocal实现的,每个线程都会维护自己独立的事务上下文。这种设计在单线程环境下能够很好地工作,但在多线程场景下会面临挑战。

多线程调用导致事务失效的原因

  1. 线程隔离的事务上下文

    • Spring将事务状态存储在ThreadLocal变量中
    • 新创建的线程无法访问父线程的ThreadLocal变量
    • 导致子线程无法继承父线程的事务上下文
  2. 典型失效场景示例

   @Transactionalpublic void parentMethod() {// 主线程中的数据库操作1repository.save(entity1);new Thread(() -> {// 子线程中的数据库操作2repository.save(entity2);  // 这个操作不会在事务中执行}).start();}

解决方案与实践建议

  1. 避免在事务方法中创建新线程

    • 这是最直接有效的解决方案
    • 将多线程逻辑移到事务边界之外
  2. 使用编程式事务管理

   public void multiThreadOperation() {// 在外部开启事务TransactionTemplate transactionTemplate = ...;transactionTemplate.execute(status -> {// 线程1操作CompletableFuture.runAsync(() -> {// 需要显式获取事务管理器DataSourceTransactionManager txManager = ...;TransactionStatus txStatus = txManager.getTransaction(new DefaultTransactionDefinition());try {// 业务操作txManager.commit(txStatus);} catch (Exception e) {txManager.rollback(txStatus);throw e;}});// 线程2操作...return null;});}
  1. 使用分布式事务框架
    • 对于复杂的多线程事务场景
    • 可考虑Seata等分布式事务解决方案

性能考量

  1. 多线程事务会带来额外的性能开销
  2. 需要权衡并发性能提升与事务管理复杂度
  3. 建议对关键业务进行压力测试

最佳实践

  1. 尽量保持事务方法简单,避免包含复杂线程逻辑
  2. 明确划分事务边界,一个事务最好只包含一个线程的操作
  3. 对必须跨线程的事务操作进行充分测试

异常捕获与Spring事务回滚机制

问题描述

在Spring框架中,当异常被捕获处理时,事务回滚机制可能会失效。这是因为Spring的事务管理是基于AOP实现的,默认情况下只对未捕获的运行时异常(RuntimeException)和错误(Error)进行回滚。

具体原因分析

  1. 异常捕获导致事务不回滚

    • 当异常在方法内部被try-catch块捕获并处理时,Spring的事务拦截器无法感知到这个异常
    • 事务拦截器只能捕获从方法中抛出的未被处理的异常
  2. 捕获后未重新抛出异常

    • 即使捕获了异常,如果在catch块中没有重新抛出异常或没有手动回滚事务,事务也会正常提交

解决方案

  1. 在catch块中手动回滚事务
   @Transactionalpublic void someMethod() {try {// 业务代码} catch (Exception e) {// 手动回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();// 可以选择重新抛出或处理异常}}
  1. 重新抛出异常
   @Transactionalpublic void someMethod() throws SomeException {try {// 业务代码} catch (Exception e) {// 处理异常后重新抛出throw new SomeException("处理失败", e);}}
  1. 配置@Transactional注解
    • 通过rollbackFor属性指定需要回滚的异常类型
   @Transactional(rollbackFor = {Exception.class})public void someMethod() {// 方法实现}

最佳实践

  1. 对于需要事务管理的方法,尽量减少不必要的异常捕获
  2. 如果必须捕获异常,确保在catch块中正确处理事务状态
  3. 在服务层方法中抛出业务异常,在控制器层处理异常更为合理
  4. 明确配置@Transactional注解的rollbackFor属性,避免默认行为带来的意外

示例场景

@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate InventoryService inventoryService;@Transactional(rollbackFor = {BusinessException.class, Exception.class})public void placeOrder(Order order) throws BusinessException {try {// 保存订单orderRepository.save(order);// 扣减库存inventoryService.deductInventory(order);} catch (InventoryException e) {// 库存不足异常,手动回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();throw new BusinessException("库存不足,下单失败");} catch (Exception e) {// 其他异常,同样回滚事务TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();throw new BusinessException("系统异常,下单失败", e);}}
}

手动抛出异常错误详解

异常类型与事务回滚

当我们在代码中手动抛出异常时,需要特别注意异常类型与事务回滚机制之间的关系。Spring框架默认只对RuntimeException及其子类(即未检查异常)和Error类异常进行事务回滚。

常见的运行时异常示例:

  • NullPointerException:空指针异常
  • IllegalArgumentException:非法参数异常
  • IndexOutOfBoundsException:数组越界异常
  • UncheckedException:自定义的未检查异常

检查异常与事务处理

对于检查异常(Checked Exception),如以下类型,默认情况下事务不会自动回滚:

  • IOException:文件读写异常
  • SQLException:数据库操作异常
  • FileNotFoundException:文件未找到异常
  • ClassNotFoundException:类未找到异常

处理检查异常的事务回滚方案

方案一:配置回滚规则

可以通过@Transactional注解的rollbackFor属性显式指定需要回滚的异常类型:

@Transactional(rollbackFor = {IOException.class, SQLException.class})
public void businessMethod() throws IOException {// 业务逻辑
}

方案二:异常转换

将检查异常包装为运行时异常抛出:

public void processFile() {try {// 文件操作} catch (IOException e) {throw new RuntimeException("文件处理失败", e);}
}

最佳实践建议

  1. 明确区分业务异常和技术异常
  2. 对于需要事务回滚的检查异常,建议使用异常包装方式
  3. 在事务注解中显式声明需要回滚的异常类型
  4. 保持异常处理的统一风格,避免混合使用检查异常和运行时异常

通过正确理解异常类型与事务回滚的关系,可以确保在异常发生时业务数据的一致性得到保障。

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

相关文章:

  • 网站优化培训好学吗公司网站变更域名
  • 【开题答辩全过程】以 安全电子选举系统的设计与实现为例,包含答辩的问题和答案
  • ESP32项目(三、控制继电器,伺服电机,舵机)
  • Python 3 内置函数详解
  • Spring AI快速入门以及项目的创建
  • 微网站制作工具有哪些霞浦建设局总规网站
  • 免费微商城网站建设网站开发团队人员构成
  • 个人网页简单模板下载seo是怎么优化的
  • 杭州有实力的网站开发直接通过域名访问wordpress
  • 多目标识别YOLO :YOLOV3 原理
  • 【Qt】QSS
  • 反射还是代码生成?Go反射使用的边界与取舍|Go语言进阶(11)
  • 国际外贸网站建设前端自适应模板
  • 网站建设代码流程花店网站建设个人小结
  • 德阳建设公司网站网站制作里的更多怎么做
  • HandBrake:视频压缩工具
  • 建设部门的网站wordpress图片批量上传插件下载
  • 致远OA配置HTTPS访问避坑帖
  • 快速搭建网站视频wordpress托管在哪里
  • AssemblyScript 入门教程(5):深入理解 TypedArray
  • 【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
  • STM32G474单片机开发入门(六)定时器TIMER详解及实战含源码
  • C++进阶(9)——智能指针的使用及其原理
  • 个人写HTOS移植shell
  • 【开发工具】Windows1011远程Ubuntu18及以上桌面
  • 输入法网站设计怎么自己制作图片
  • STM32 Flash 访问加速器详解(ART Accelerator)
  • stm32 freertos下基于hal库的模拟I2C驱动实现
  • 成都微网站访问wordpress速度慢
  • 意识形态网站建设怎么做网络平台