Spring高手之路24——事务类型及传播行为实战指南

文章目录

  • 1. 编程式事务(不推荐)
  • 2. 声明式事务(推荐)
  • 3. 事务的传播行为(复杂混合事务场景及时序图说明)
    • 3.1 NESTED和REQUIRES_NEW传播行为的区别

1. 编程式事务(不推荐)

定义:编程式事务是指通过显式的编程代码来管理事务的开始、提交和回滚。开发者需要手动控制事务的每个步骤。

优点

  • 更加灵活:开发者可以根据具体的业务逻辑细节对事务进行精细控制。
  • 适用于需要精细控制的事务逻辑:当事务行为需要根据特定条件进行复杂控制时,编程式事务更为合适。

缺点

  • 代码冗长:需要手动编写大量的事务管理代码,增加了代码复杂性。
  • 易出错:手动管理事务容易导致漏写提交或回滚的代码,增加了发生错误的风险。

示例(以Spring的编程式事务为例):

import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;public class TransactionService {private final PlatformTransactionManager transactionManager;public TransactionService(PlatformTransactionManager transactionManager) {this.transactionManager = transactionManager;}public void executeInTransaction() {TransactionDefinition def = new DefaultTransactionDefinition();TransactionStatus status = transactionManager.getTransaction(def);try {// 业务逻辑transactionManager.commit(status);} catch (Exception e) {transactionManager.rollback(status);throw e;}}
}

  这段代码展示了如何使用Spring进行编程式事务管理。executeInTransaction方法中,首先创建了一个事务定义和事务状态。然后,在try代码块中执行业务逻辑,并在成功时提交事务。如果发生异常,则回滚事务。通过这种方式,可以精细控制事务的开始、提交和回滚,适用于需要复杂事务控制的场景。

2. 声明式事务(推荐)

定义:声明式事务是通过配置或注解的方式来管理事务。开发者无需手动编写事务管理代码,事务的控制交由框架处理。

优点

  • 简洁明了:使用注解或配置文件即可实现事务管理,代码更加简洁。
  • 降低出错率:自动管理事务,减少手动管理带来的错误。

缺点

  • 灵活性较差:声明式事务在面对非常复杂的事务逻辑时,可能不够灵活,但可以通过结合使用不同的事务传播行为来部分解决这个问题。

示例(以Spring的声明式事务为例):

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class TransactionService {@Transactionalpublic void executeInTransaction() {// 业务逻辑}
}

Spring中,通常推荐使用声明式事务,因为它更加简洁并且可以充分利用Spring框架的事务管理功能。在需要复杂事务控制时,可以考虑使用编程式事务。

3. 事务的传播行为(复杂混合事务场景及时序图说明)

  • REQUIRED:如果当前没有事务,则创建一个新的事务;如果已经存在一个事务,则加入当前事务。
  • REQUIRES_NEW:每次都创建一个新的事务,如果当前已经有一个事务,则挂起当前事务。挂起当前事务的意思是,当前事务的执行暂停,待新事务完成后再恢复执行。新事务提交后,主事务回滚不会影响这个新事务。
  • NESTED:如果当前有事务,则在当前事务中嵌套一个事务,若外部事务回滚,则嵌套事务也会回滚;如果当前没有事务,则创建一个新的事务。
  • MANDATORY:必须在一个现有事务中运行,如果当前没有事务,则抛出异常。
  • NEVER:不能在事务中运行,如果当前有事务,则抛出异常。
  • NOT_SUPPORTED:当前方法不支持事务,如果当前有事务,则将事务挂起。
  • SUPPORTS:如果当前有事务,则加入该事务;如果当前没有事务,也可以非事务方式运行。

  对于需要部分事务回滚的复杂场景,Spring中的声明式事务确实可以通过传播行为来实现一定的灵活控制。以下是一个详细的示例,展示如何使用常见的传播行为来实现部分事务回滚。

复杂混合事务场景示例:

假设有一个订单处理系统,包含以下步骤:

  1. 创建订单
  2. 扣减库存
  3. 发送确认邮件

我们希望在处理过程中:

  • 如果创建订单失败,整个事务回滚。
  • 如果扣减库存失败,只回滚扣减库存这部分,不影响订单创建。
  • 发送确认邮件可以在一个独立的事务中进行,即使失败也不影响前面的步骤。

代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class OrderService {@Autowiredprivate InventoryService inventoryService;@Autowiredprivate EmailService emailService;@Transactional(propagation = Propagation.REQUIRED)public void processOrder(Order order) {// Step 1: 创建订单(主事务)createOrder(order);try {// Step 2: 扣减库存(嵌套事务)inventoryService.deductInventory(order);} catch (Exception e) {// 仅回滚扣减库存这部分,不影响订单创建System.err.println("扣减库存失败: " + e.getMessage());}// Step 3: 发送确认邮件(新事务)emailService.sendOrderConfirmation(order);}@Transactional(propagation = Propagation.REQUIRES_NEW)public void createOrder(Order order) {// 创建订单的逻辑// 如果失败,抛出异常,整个事务回滚if (order == null) {throw new RuntimeException("订单创建失败");}}
}

库存服务InventoryService

@Service
public class InventoryService {@Transactional(propagation = Propagation.NESTED)public void deductInventory(Order order) {// 扣减库存的逻辑// 如果失败,抛出异常,仅回滚此嵌套事务if (order.getItems().isEmpty()) {throw new RuntimeException("库存扣减失败");}}
}

邮件服务EmailService

@Service
public class EmailService {@Transactional(propagation = Propagation.REQUIRES_NEW)public void sendOrderConfirmation(Order order) {// 发送确认邮件的逻辑// 失败也不会影响主事务if (order.getEmail() == null) {throw new RuntimeException("邮件发送失败");}}
}

解释

  • 创建订单
    使用 REQUIRED 传播行为,作为主事务。如果失败,会抛出异常,导致整个事务回滚。

  • 扣减库存
    使用 NESTED 传播行为,在主事务内创建一个嵌套事务。如果扣减库存失败,只会回滚这个嵌套事务,不会影响到主事务。

  • 发送确认邮件
    使用 REQUIRES_NEW 传播行为,总是创建一个新的事务。即使发送邮件失败,也不会影响前面的事务。

通过结合使用事务不同的传播行为,可以在声明式事务中实现复杂的事务管理需求,如部分事务回滚。

整个事务处理过程时序图如下:

在这里插入图片描述

时序图解释

  1. 客户端调用 OrderServiceprocessOrder 方法开始主事务。
  2. OrderService 中创建订单,使用 REQUIRED 传播行为。
  3. 如果订单创建成功,调用 InventoryService 扣减库存,使用 NESTED 传播行为。如果库存扣减失败,只回滚嵌套事务,不影响主事务。
  4. 无论库存扣减是否成功,调用 EmailService 发送确认邮件,使用 REQUIRES_NEW 传播行为。即使邮件发送失败,也不影响主事务。
  5. 如果订单创建失败,回滚主事务,并且所有嵌套事务也会回滚,但独立的新事务不会受到影响。

3.1 NESTED和REQUIRES_NEW传播行为的区别

有人可能疑惑了,这里NESTEDREQUIRES_NEW的传播行为看起来很像,这里详细对比一下。

  1. 事务关系:

REQUIRES_NEW

  • 创建一个独立的新事务,与外部事务无关。
  • 如果当前有事务,暂停当前事务,启动一个新事务。
  • 新事务提交或回滚后,外部事务继续。

NESTED

  • 在当前事务内创建一个嵌套事务。
  • 嵌套事务依赖于外部事务,嵌套事务提交必须等待外部事务提交。
  • 如果当前没有事务,则行为与 REQUIRED 相同,创建一个新事务。
  1. 回滚和提交行为

REQUIRES_NEW

  • 回滚行为:如果新事务失败,只回滚新事务,不影响外部事务。
  • 提交行为:新事务提交后,外部事务继续。即使外部事务回滚,新事务的提交也不会受到影响。

NESTED

  • 回滚行为:如果嵌套事务失败,只回滚嵌套事务,不影响外部事务。
  • 提交行为:嵌套事务在外部事务提交时才真正提交。如果外部事务回滚,嵌套事务也会回滚。
  1. 使用场景

REQUIRES_NEW

  • 适用于需要独立事务的场景,例如记录日志或发送通知,这些操作应独立完成,不受主事务影响。

NESTED

  • 适用于部分独立处理但依赖于外部事务的场景,例如部分业务操作需要独立回滚,但整体上需要保持一致性。

欢迎一键三连~

有问题请留言,大家一起探讨学习

----------------------Talk is cheap, show me the code-----------------------

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/148047.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

MAC激活Typora以及禁止成功激活弹窗的方法

激活 Typora 首先在官网下载 Typora 的最新版 并且安装。 打开以下目录 /Applications/Typora.app/Contents/Resources/TypeMark/page-dist/static/js/ 注意在 Applications 中,需要对 Typora 右键选择 Show Packages Contents 即可进入 Typora.app。 在该目录的文…

C++自动驾驶面试核心问题整理

应用开发 概述:比较基础,没啥壁垒,主要有linux开发经验即可 问题:基础八股,如计算机网络、操作系统、c11等基础三件套;中等难度算法题1-2道。 中间件开发(性能优化) 概述&am…

快递物流查询-快递查询-快递单号查询-快递物流单号查询-快递物流轨迹查询-快递物流查询接口

快递物流查询接口(API)是一种允许开发者通过编程方式实时查询快递物流信息的服务。这些接口通常集成了多家快递公司的物流数据,为电商平台、物流管理系统、个人用户等提供便捷的物流查询服务。以下是关于快递物流查询接口的一些详细介绍&…

哪有什么三教九流,物以类聚罢了——kmeans聚类算法

观察人类社会,亦或说车水马龙中的光怪陆离,不难发现《马原》中介绍的人类社会中的个体,总是通过某种方面的“类似”聚在一起,文学上称这种现象叫做物以类聚,人以群分。 一.引言 前文提到,每个数据项&#x…

SpringBoot项目License证书生成与验证(TrueLicense) 【记录】

SpringBoot项目License证书生成与验证(TrueLicense) 【记录】 在非开源产品、商业软件、收费软件等系统的使用上,需要考虑系统的使用版权问题,不能随便一个人拿去在任何环境都能用。应用部署一般分为两种情况: 应用部署在开发者自己的云服务…

Qt笔记(十七)cmake编译Qt项目

Qt笔记(十七)cmake编译Qt项目 1. 文件内容与文件结构1.1.文件目录1.2. CMakeLists.txt内容1.3. main.cpp文件1.4. mouseevent.h1.5. mouseevent.cpp1.6. 生成Visual Studio项目后编译报错1.7. 界面显示中文乱码问题 1. 文件内容与文件结构 1.1.文件目录…

jdk11特性介绍

JDK 11(也称为Java 11)是Java平台的一个重要版本,它引入了许多新特性和改进,旨在提高开发者的生产力和Java平台的性能。以下是一些JDK 11的主要特性: 局部变量类型推断(Local-Variable Syntax for Lambda P…

2009考研数学真题解析-数二:

第一题: 解析:先找间断点:分母不能等于0,分母是sinΠx, 因此不难看出间断点是x0,-1,-2,-3。。。。。 接着一个一个来算这些点是什么间断点。 ,从x趋于2开始,分…

JavaScript是如何来的~~

文章目录 前言一、网络的诞生 ( The birth of the Web )二、Mosaic 浏览器三、Netscape 浏览器四、JavaScript的诞生 ~ 千呼万唤始出来总结 前言 例如:想要了解一门语言的发展历程,首先你得知道它是怎么来的,所以本文开篇介绍了网络的基本发…

智能BI平台项目

1.项目介绍 BI商业智能:数据可视化、报表可视化系统 4)发布订阅 Resource 是基于名称进行查找的,而Spring框架中更常用的 Autowired 则是基于类型进行查找的。如果找不到匹配的bean,Autowired 会抛出异常,而 Resource…

EAGLE——探索混合编码器的多模态大型语言模型的设计空间

概述 准确解释复杂视觉信息的能力是多模态大型语言模型 (MLLM) 的关键重点。最近的研究表明,增强的视觉感知可显著减少幻觉并提高分辨率敏感任务(例如光学字符识别和文档分析)的性能。最近的几种 MLLM 通过利用视觉编码器的混合来实现这一点…

网络层协议 —— IP协议

目录 0.前言 1.IP协议的格式 2.IP地址 2.1IP地址的划分 国际间IP地址的划分 公有IP 私有IP 特殊的IP地址 国内IP地址的划分 2.2IP地址不足问题 2.3IP地址的功能 2.4如何使用IP地址 2.5IP地址的构成 3.网段划分 以前的方案 现在的方案 4.认识宏观网络 5.路由 …

SpringCloud config native 配置

SpringCloud config native 配置 1.概述 最近项目使用springCloud 框架,使用config搭建git作为配置中心。 在私有化部署中,出现很多比较麻烦的和鸡肋的设计。 每次部署都需要安装gitlab 有些环境安装完gitlab,外面不能访问,不给开…

QT实现升级进度条页面

一.功能说明 在Qt中实现固件升级的进度条显示窗口,你可以通过创建一个自定义的对话框(Dialog)来完成。这个对话框可以包含一个进度条(QProgressBar)、一些文本标签(QLabel)用于显示状态信息&am…

SSL 最长签发时间是多久?

在当今数字化的时代,网络安全变得至关重要。为了确保数据在网络传输中的安全性,SSL(Secure Sockets Layer,安全套接层)证书被广泛应用。那么,SSL最长签发时间是多久呢? SSL证书是一种数字证书&…

差分数组介绍

差分数组 差分数组介绍定义性质性质1: 计算数列第i项的值性质2: 计算数列第i项的前缀和应用场景差分数组具体示例【leetcode】370.区间加法题目描述题解【leetcode】1109. 航班预订统计题目描述题解【leetcode】2848.与车相交的点题目描述题解差分数组介绍 定义 对于已知有n个…

C#如何把写好的类编译成dll文件

1 新建一个类库项目 2 直接改写这个Class1.cs文件 3 记得要添加Windows.Forms引用 4 我直接把在别的项目中做好的cs文件搞到这里来,连文件名也改了(FilesDirectory.cs),这里using System.Windows.Forms不会报错,因为前…

制造解法 Manufactured Solutions 相关的论文的阅读笔记

Verification of Euler/Navier–Stokes codes using the method of manufactured solutions https://doi.org/10.1002/fld.660 粘性项与扩散项之间的平衡 For the Navier–Stokes simulations presented herein, the absolute viscosity is chosen to be a large constant va…

【Java】掌握Java:基础概念与核心技能

文章目录 前言:1. 注释2. 字面量3. 变量详解3.1 变量的定义3.2 变量里的数据存储原理3.3 数据类型3.4 关键字、标识符 4. 方法4.1 方法是啥?4.2 方法的完整定义格式4.3 方法如何使用:4.4 方法的其他形式4.5 方法的其他注意事项4.5.1 方法是可…

如何充分使用芝士AI呢?一文讲清楚助力论文完成无忧

为了解决各位学弟学妹们的论文烦恼,助力大家毕业无忧,芝士AI由985硕博团队的学长学姐们潜心研发出来的一款集齐论文选题、开题报告、论文初稿、论文查重、论文降重、论文降AIGC率、论文答辩稿、论文答辩PPT,一站式解决困扰大家已久的论文问题…