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

探究Spring事务:了解失效场景及应对策略

在现代软件开发中,数据的一致性和完整性是至关重要的。为了保证这些特性,Spring框架提供了强大的事务管理机制,让开发者能够更加自信地处理数据库操作。然而,事务并非银弹,存在一些失效的情景,本文将带您深入探究Spring事务及其失效场景,并为您呈现应对策略。

spring事务失效的场景

_20230804232601.png

@Transactional概述

在Spring Boot中,@Transactional是一个用于声明式事务管理的注解。事务是一种用来维护数据库操作的一致性和隔离性的机制,确保在一组操作中,要么所有操作都成功提交,要么所有操作都回滚,以保持数据的完整性。@Transactional注解让你能够在方法级别上定义事务的行为,而无需显式编写事务管理代码。

@Transactional注解的详细解释:

  • 标记事务起点:@Transactional注解放在方法上,表示该方法应该在一个事务内执行。当方法被调用时,Spring会自动开始一个事务。

  • 事务属性: @Transactional注解支持多个属性,用于配置事务的各个方面。一些常用的属性包括:

    • isolation:指定事务的隔离级别,定义了事务之间的可见性。例如,Isolation.READ_COMMITTED表示读已提交的隔离级别。
    • propagation:定义了事务的传播行为,即方法被另一个事务方法调用时如何处理事务。例如,Propagation.REQUIRED表示如果已存在事务,则沿用该事务,否则创建一个新的事务。
    • readOnly:指定事务是否只读。如果只读,可以优化事务处理,因为不需要考虑写操作。
    • timeout:定义事务的超时时间,超过该时间未提交则自动回滚。
    • rollbackFornoRollbackFor:指定在哪些异常情况下回滚事务或不回滚事务。
  • 嵌套事务: 如果在方法中调用了另一个被@Transactional注解标记的方法,那么默认情况下会共享外部方法的事务。如果希望内部方法有自己的事务,可以使用Propagation.REQUIRES_NEW传播行为。

  • 回滚策略: 默认情况下,Spring会将未捕获的运行时异常(RuntimeException及其子类)作为触发事务回滚的标志。你也可以通过rollbackFor属性指定哪些异常触发回滚。

  • 应用范围: @Transactional注解可以用于类级别(作用于所有方法)或方法级别(作用于单个方法),具体取决于你的需求。

  • 生效方式: @Transactional注解依赖于Spring的AOP(面向切面编程)技术,它会在运行时通过代理机制来拦截方法调用,并根据注解的配置来管理事务。

TransactionSynchronizationManager辅助打印事务

在Spring Boot中,你可以使用TransactionSynchronizationManager来获取有关已开启事务的信息。TransactionSynchronizationManager是Spring的一个工具类,用于管理和监视事务的状态。要打印已开启的事务,你可以通过以下步骤进行:

  • 导入必要的类: 首先,确保你的类中导入了TransactionSynchronizationManager类。
import org.springframework.transaction.support.TransactionSynchronizationManager;
  • 打印当前事务名称或者状态
boolean isTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();if (isTransactionActive) {System.out.println("An active transaction is present.");System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
} else {System.out.println("No active transaction.");
}

失效场景详解

  • 未被Spring管理的对象

未被标记为@Component、@Service、@Repository或其他Spring管理注解的普通Java类不会被Spring自动管理。

import org.springframework.transaction.annotation.Transactional;public class NoManageService {
/**
import org.springframework.transaction.annotation.Transactional;public class NoManageService {/*** 事务不生效场景:未被Spring管理的对象*/@Transactionalpublic void doHandle() {// 一通处理}
}}
  • 异常未被正确捕获和抛出

异常被捕获但未重新抛出,事务将不会回滚。

    /*** 事务不生效场景:异常未被正确捕获和抛出*/@Transactional(rollbackFor = Exception.class)public void method1(){try {//一通处理猛如虎}catch (Exception e){//异常只吞不吐不回滚}}
  • 在非公共方法上使用@Transactional
    /*** 事务不生效场景:在非公共方法上使用@Transactional*/@Transactional(rollbackFor = Exception.class)private void method2(){//一通处理猛如虎}
  • 事务方法内部调用

当事务方法内部通过普通的方法调用,而不是通过Spring管理的Bean调用其他带有@Transactional注解的方法时,事务可能失效。这是因为Spring的事务机制是基于代理实现的,只有通过代理对象调用的方法才能被AOP拦截并应用事务。

    /*** 事务不生效场景:事务方法内部调用,未被AOP拦截*/public void method3(){method5();}@Resourceprivate TestService testService;/*** 事务生效,使用自我引用的方式调用: 如果在同一个类中需要在事务内部调用其他事务方法,* 可以通过自我引用的方式来调用,以便事务代理可以生效。*/public void method4(){testService.method5();}@Transactional(rollbackFor = Exception.class)public void method5(){//一通处理猛如虎}
  • 事务传播机制配置错误

如果在方法中调用了另一个被@Transactional注解标记的方法,那么默认情况下会共享外部方法的事务。如果希望内部方法有自己的事务,可以使用Propagation.REQUIRES_NEW传播行为。

    /*** method6中调用method7,会共享method6方法的事务*/@Transactional(rollbackFor = Exception.class)public void method6(){//获取当前事务名称,若未开启事务,则为nullString  tranName = TransactionSynchronizationManager.getCurrentTransactionName();log.info("method6事务名称=======》{}",tranName);//一通处理猛如虎testService.method7();}@Transactional(rollbackFor = Exception.class)public void method7(){//获取当前事务名称,若未开启事务,则为nullString  tranName = TransactionSynchronizationManager.getCurrentTransactionName();log.info("method7事务名称=======》{}",tranName);//一通处理猛如虎}

调用method6则会打印

23:04:48.861 [http-nio-8180-exec-1] INFO  c.x.t.TestServiceImpl - [method6,69] - method6事务名称=======》cn.xj.transactional.TestServiceImpl.method6
23:04:48.862 [http-nio-8180-exec-1] INFO  c.x.t.TestServiceImpl - [method7,77] - method7事务名称=======》cn.xj.transactional.TestServiceImpl.method6
    /*** method8中调用method9,method9会重新开启个事务*/@Transactional(rollbackFor = Exception.class)public void method8(){//获取当前事务名称,若未开启事务,则为nullString  tranName = TransactionSynchronizationManager.getCurrentTransactionName();log.info("method8事务名称=======》{}",tranName);//一通处理猛如虎testService.method9();}@Transactional(rollbackFor = Exception.class,propagation= Propagation.REQUIRES_NEW)public void method9(){//获取当前事务名称,若未开启事务,则为nullString  tranName = TransactionSynchronizationManager.getCurrentTransactionName();log.info("method9事务名称=======》{}",tranName);//一通处理猛如虎}

调用method8则会打印

23:12:51.058 [http-nio-8180-exec-1] INFO  c.x.t.TestServiceImpl - [method8,93] - method8事务名称=======》cn.xj.transactional.TestServiceImpl.method8
23:12:51.086 [http-nio-8180-exec-1] INFO  c.x.t.TestServiceImpl - [method9,101] - method9事务名称=======》cn.xj.transactional.TestServiceImpl.method9

总结

Spring事务为我们提供了一个强大的工具来维护数据的一致性和完整性。然而,在使用过程中,了解事务失效的场景以及应对策略同样重要。通过合理配置事务传播行为、异常处理以及使用注解管理事务,我们能够更好地应对各种情况,确保系统的稳定性和可靠性。

http://www.lryc.cn/news/109213.html

相关文章:

  • Maven Manifold 条件编译
  • 4.数组与基本数学函数
  • python与深度学习(十六):CNN和宝可梦模型二
  • PTA 1030 Travel Plan
  • MFC、Qt、WPF?该用哪个?
  • 使用logback记录日志
  • 企业工程项目管理系统源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理) em
  • 【安装】XMind2022XMind2020安装教程(资源)
  • Windows下QT Creator安装MinGW 32bit编译器
  • Emacs之解决键值绑定冲突问题(一百二十三)
  • 瞄准产业应用,大模型加持的深兰科技AI虚拟数字人落地业务场景
  • 【网络基础进阶之路】基于MGRE多点协议的实战详解
  • Spark、RDD、Hive 、Hadoop-Hive 和传统关系型数据库区别
  • [运维]python 启用http 文件服务
  • electron-builder 打包 exe 异常错误集锦
  • 14-5_Qt 5.9 C++开发指南_基于HTTP 协议的网络应用程序
  • Kotlin委托
  • 分布式协议与算法——CAP理论、ACID理论、BASE理论
  • 接口测试 Jmeter 接口测试 —— 请求 Headers 与传参方式
  • 【redis】redis部署1主2从3哨兵demo搭建示例
  • C++数据结构之平衡二叉搜索树(一)——AVL的实现(zig-zag/左右双旋/3+4重构)
  • 免疫疗法勘察兵——DC细胞
  • Django实现音乐网站 ⑷
  • 2023年华数杯数学建模C题思路 - 母亲身心健康对婴儿成长的影响
  • openGauss学习笔记-30 openGauss 高级数据管理-别名
  • C#实现多线程局域网扫描器的思路与具体代码
  • Redis秒杀:一人一单问题及初步解决
  • python 数据分析面试题:求分组排第n名的记录数据
  • eclipse常用快捷键
  • 什么是OCR?OCR技术详解