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

news2024/9/23 2:57:01

文章目录

  • 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 {

    @Transactional
    public 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 {

    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private 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.coloradmin.cn/o/2156405.html

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

相关文章

如何从 Nutanix 迁移至 SmartX 超融合?解读 4 类迁移方案和 2 例迁移实践

2022 年底,Nutanix(路坦力)正式宣布将中国市场交由合作伙伴(联想)主导销售,并于 2023 年 8 月完成全面转型。转型后,虽然中国用户依旧可以使用 Nutanix 产品,但在软件的续保和维保方…

企业EMS -能源管理系统-能源管理系统源码-能源在线监测平台

能源管理系统是以帮助工业生产企业在扩大生产的同时,合理计划和利用能源,降低单位产品能源消耗,提高经济效益,降低CO2排放量为目的信息化管控系统。 我国能源管理从上世纪80年代中期开始,通过“能量平衡测试”、“能源…

安卓数据存储——SharedPreferences

共享参数 SharedPreferences 1、sharedPreferences是Android的一个轻量级存储工具,采用的存储结构是key - value的键值对方式 2、共享参数的存储介质是符合XML规范的配置文件。保存路径是:/data/data/应用包名/shared_prefs/文件名.xml 使用场景&…

【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 方法是可…

WebMagic:强大的Java网络爬虫框架

上班苦上班累,上班就想打瞌睡。 在当今信息爆炸的时代,数据的获取和处理变得越来越重要。网络爬虫作为获取网络数据的重要工具,已经成为许多开发者和数据科学家的必备技能。今天,我们将介绍一个广受欢迎的Java网络爬虫框架——We…

2024PDF内容修改秘籍:工具推荐与技巧分享

现在我们使用PDF文档的频率越来越高了,很多时候收到的表格之类的资料也都是PDF格式的,如果进行转换之后编辑再转换为PDF格式还是有点麻烦的,那么pdf怎么编辑修改内容呢?这篇文章我将介绍几款可以直接编辑PDF文件的工具来提高我们的…

鸿蒙开发(NEXT/API 12)【跨设备互通NDK开发】协同服务

跨设备互通提供跨设备的相机、扫描、图库访问能力,平板或2in1设备可以调用手机的相机、扫描、图库等功能。 说明 本章节以拍照为例展开介绍,扫描、图库功能的使用与拍照类似。 用户在平板或2in1设备上使用富文本类编辑应用(如:…

JVM —— 类加载器的分类,双亲委派机制

文章目录 一、类加载器的分类【理解】1.1 概述1.2 JDK8及之前的版本1.2.1 启动类加载器1.2.2 扩展类加载器和应用程序类加载器扩展类加载器应用程序类加载器 1.3 JDK9之后的类加载器1.4 ClassLoader 中的两个方法【应用】 二、双亲委派模型【理解】2.1 什么是双亲委派机制面试题…

在vue中嵌入vitepress,基于markdown文件生成静态网页从而嵌入社团周报系统的一些想法和思路

什么是vitepress vitepress是一种将markdown文件渲染成静态网页的技术 其使用仅需几行命令即可 //在根目录安装vitepress npm add -D vitepress //初始化vitepress,添加相关配置文件,选择主题,描述,框架等 npx vitepress init //…

9.20日学习记录及相关问题解答

部分一 今天看了一本古老的书。学到了一些有关计算机的远古的知识。弥补了一些之前没有意识到的空白点。 原来上个世纪就有AI这个东西了 现阶段的主流模式,在许多年前其实是将来要发展的对象。 B/S指的是客户机/服务器结构模式 C/S是在B/S基础上发展过来的。三层结…

兼容多个AI应用接口,支持用户自定义切换AI接口

项目背景 2023年ChatGPT横空出世,给IT行业造成了巨大的反响。我第一次发现这个ChatGPT有着如此神奇的功能(智能对话,知识问答,代码生成,逻辑推理等),我感到非常吃惊!经过一番学习和…

一文看懂 Python 正则表达式,解决你的字符串难题!(Python正则表达式使用指南)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Re正则 📒📝 re 模块简介📝 正则表达式语法总结📝 re 模块参数总结📝 常用方法📝 正则表达式的技巧与注意事项📝 使用 `re.compile()` 实现编译模式⚓️ 相关链接 ⚓️📖 介绍 📖 在编程世界中,有一种强大的…

Lanterns (dp 紫 线段树 二分 维护dp)

Lanterns - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 让所有点被覆盖,那么状态可以设计成覆盖一段前缀,并且中间不允许出现断点 由于CF崩了,所以暂时没提交代码。 记f(i) 为前 i 个灯笼点亮的最长前缀。 由于答案具有保留性&#xff…

9.22算法题数组篇

数组的遍历 485.最大连续1的个数 题解 class Solution {public int findMaxConsecutiveOnes(int[] nums) {int maxcount0,count0;for (int i 0;i<nums.length;i){if(nums[i]1){count;}else{maxcountMath.max(maxcount,count);count0;}}maxcountMath.max(maxcount,count);r…

基于kubernetes-nmstate配置节点网络

kubernetes-nmstate 简介 kubernetes-nmstate 通过 Kubernetes API 驱动的声明式节点网络配置。 随着混合云的出现&#xff0c;节点网络设置变得更加具有挑战性。不同的环境有不同的网络要求。 容器网络接口&#xff08;CNI&#xff09;标准实现了不同的解决方案&#xff0c;…

【MySQL】 索引

MySQL与磁盘存储 MySQL就是提供数据存储服务的&#xff0c;而最终存储的位置就是磁盘&#xff0c;但是磁盘存储速度慢&#xff0c;所以MySQL如何与磁盘交互&#xff0c;提高数据存储效率&#xff0c;即是MySQL和磁盘交互。 磁盘基础知识回顾 物理结构 磁道&#xff1a;磁盘是…

AI运动小程序开发常见问题集锦一

截止到现在写博文时&#xff0c;我们的AI运动识别小程序插件已经迭代了23个版本&#xff0c;成功应用于健身、体育、体测、AR互动等场景&#xff1b;为了让正在集成或者计划进行功能扩展优化的用户&#xff0c;少走弯路、投入更少的开发资源&#xff0c;我们归集了一部分集中的…

想复制其他设备上的软件?看这里!-未来之窗行业应用跨平台架构

一、多好用的软件&#xff0c;已经没有apk安装包&#xff0c;很遗憾 1. 用户体验受损 &#xff1a;对于那些曾经依赖并喜爱这些软件的用户来说&#xff0c;无法再获取和使用它们&#xff0c;极大地影响了用户的日常体验和工作效率。 2. 功能缺失 &#xff1a;可能导致特定的功…

Kubernetes实战——集群监控和可视化管理

目录 一、Kube-Prometheus 1、版本兼容性介绍 2、安装 kube-prometheus 3、安装Ingress&#xff0c;实现访问 二、K8s安装ELK日志收集 1、安装Elasticsearch 2、安装Logstash 3、安装Filebeat 4、安装Kibina 三、Dashboard安装与使用 1、安装 2、创建token 3、使用 …

【算法业务】互联网风控业务中的续贷审批模型(融合还款意愿分层的逾期风险识别模型)

1、背景说明 本文旨在提出一种针对风控催收受限情况下&#xff0c;如何提升风控审批模型的风险识别能力&#xff0c;以缓解贷后催收的压力&#xff0c;降低贷款资金坏账的风险。这篇工作依然是很早期的项目&#xff0c;分享的目的一方面做笔记&#xff0c;另一方面则是希望其中…