2023.12.9 关于 Spring Boot 事务传播机制详解

news2024/11/21 2:31:27

目录

事务传播机制

七大事务传播机制 

支持当前调用链上的事务

Propagation.REQUIRED

Propagation.SUPPORTS

Propagation.MANDATORY

不支持当前调用链上的事务

Propagation.REQUIRES_NEW

Propagation.NOT_SUPPORTED

Propagation.NEVER

嵌套事务

Propagation.NESTED

前置工作

初始化数据库

初始化 实体类

初始化 Mapper 接口

初始化 XML 文件

 重点理解部分

NESTED 和 REQUIRED_NEW 的区别

NESTED 和 REQUIRED 的区别


事务传播机制

  • 事务的传播机制是指在多个事务方法之间调用时,事务如何在这些方法之间传播

七大事务传播机制 

支持当前调用链上的事务

Propagation.REQUIRED

  • 默认的事务传播级别
  • 如果当前没有事务,则新建一个事务,如果当前存在事务,则加入该事务

实例理解


Propagation.SUPPORTS

  • 如果当前方法没有事务,就以非事务方式执行,如果已经存在一个事务中,则加入到这个事务中


Propagation.MANDATORY

  • 如果当前方法没有事务,则抛出异常,如果已经存在一个事务中,则加入到这个事务中

不支持当前调用链上的事务

Propagation.REQUIRES_NEW

  • 创建一个新事务,如果存在当前事务,则挂起当前事务

Propagation.NOT_SUPPORTED

  • 以非事务方式执行,如果存在当前事务,则挂起当前事务

Propagation.NEVER

  • 以非事务方式执行,如果当前事务存在,则抛出异常

嵌套事务

Propagation.NESTED

  • 如果当前存在事务,则在嵌套事务中执行,否则与 REQUIRED 的操作一样

前置工作

  • 此处为了方便下文进行代码测试理解
  • 我们先将准备工作做好

初始化数据库

  • 创建一个 user 表,并添加几条用户信息


初始化 实体类

  • 创建 User 实体类 与 数据库的 user 表字段名相对应
import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private int age;
    private String password;
    private int state;
}

初始化 Mapper 接口

  • 初始化 UserMapper 接口,此处我们添加一个 add 方法

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface UserMapper {
//    新增用户信息
    Integer add(User user);
}

初始化 XML 文件

  • 在与 UserMapper 接口相对应的 XML 文件中添加上与 add 方法 相对应的 sql 语句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">

    <insert id="add">
        insert into user(name,age,password) values(#{name},#{age},#{password})
    </insert>
</mapper>

 重点理解部分

NESTED 和 REQUIRED_NEW 的区别

  • REQUIRED_NEW 是新建一个事务并且新开始的这个事务与原有事务无关
  • 而 NESTED 是当前存在事务时会开启一个嵌套事务
  • 在 NESTED 情况下,父事务回滚时,子事务也会回滚
  • 而 REQUIRED_NEW 情况下,原有事务回滚,不会影响新开启的事务

实例理解

  • 我们创建一个 userController 类,并给 addUser 方法加上 REQUIRED 类型的事务
  •  此时的 addUser 方法,将自动创建一个事务A
  • 注意我们在 addUser 中加入了一个算数异常
import com.example.demo.entity.User;
import com.example.demo.service.LoggerService;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user2")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public String addUser(User user) {
//        调用 userService 的 add 方法
        int result = userService.add(user);
        int c = 10/0;
        return "add 方法:" + (result == 1 ? "新增用户成功": "新增用户失败");
    }
}
  • 可以看到 userController 类中调用了 add 方法,该方法在 userService 中
  • 此处我们给 add 方法加上 NESTED 类型的事务
  • 因为 addUser 已经创建了一个事务A,所以此处的 add 方法将在 事务A中创建一个嵌套事务
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
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 UserService {

    @Autowired
    private UserMapper userMapper;

    //    新增用户信息
    @Transactional(propagation = Propagation.NESTED)
    public int add(User user) {
        int result = userMapper.add(user);
        return result;
    }
}

运行结果:

  • 在浏览器中输入对应的 URL 来访问 addUser 方法
  • 此时我们关注的是 在 NESTED 情况下,父事务回滚时,子事务也会回滚

  • 此处正好为 addUser 方法发生了 算数异常,从而进行了回滚操作
  • 且在抛出算数异常前,就已经调用了 userService.add 方法
  • 如果此处数据库中插入了新用户信息,则代表子事务未进行回滚操作

  • 此时我们查看 user 表,发现新用户未插入,即子事务进行了回滚操作,与预期结果一致

调整 add 方法的事务传播机制

  • 我们将 add 方法改为 REQUIRES_NEW 类型的事务
  • 因为 addUser 已经创建了一个事务A,所以此处的 add 方法将会把 事务A 挂起,另外创建一个 事务B
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
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 UserService {

    @Autowired
    private UserMapper userMapper;

    //    新增用户信息
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int add(User user) {
        int result = userMapper.add(user);
        return result;
    }
}

运行结果:

  • 在浏览器中输入对应的 URL 来访问 addUser 方法
  • 此时我们关注的是 REQUIRED_NEW 情况下,原有事务回滚,不会影响新开启的事务

  • 查看 user 表发现新增了一条用户信息,即新开启的事务B 未进行回滚,与预期结果一致


NESTED 和 REQUIRED 的区别

  • REQUIRED 的情况下,调用方存在事务时,则被调用发和调用方使用同一个事务
  • 那么被调用方出现异常时,由于共用同一个事务,所以无论是否 catch 异常,事务都会回滚
  • 而在 NESTTED 情况下,被调用方发生异常时,调用方可以 catch 其异常,这样只有子事务回滚,父事务不回滚

实例理解

  • 我们创建一个 userController 类,并给 addUser 方法加上 REQUIRED 类型的事务
  • 此时的 addUser 方法,将自动创建一个事务A
  • 我们将在 userService 的 add 方法中加入一个 算数异常
  • 为了验证 REQUIRED 的情况下,被调用方出现异常时,由于共用同一个事务,所以无论是否 catch 异常,事务都会回滚
  • 如果不捕获 add 方法抛出的异常 事务A 肯定会进行回滚操作
  • 所以我们此处对算数异常进行捕获,由此来看 事务A 是否还会进行回滚操作
import com.example.demo.entity.User;
import com.example.demo.service.LoggerService;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user2")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public String addUser(User user) {
        int result = 0;
        try {
//        调用 userService 的 add 方法
            result = userService.add(user);
        }catch (Exception e){
            e.printStackTrace();
        }
        return "add 方法:" + (result == 1 ? "新增用户成功": "新增用户失败");
    }
}
  • 此处我们给 add 方法加上 REQUIRED 类型的事务
  • 因为 addUser 已经创建了一个事务A,所以此处的 add 方法将会直接加入 事务A 中
  • 此处我们在 add 方法中加入了一个算数异常
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
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 注解 代表该类会伴随着 项目的启动而注入到容器中
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    //    新增用户信息
    @Transactional(propagation = Propagation.REQUIRED)
    public int add(User user) {
        int result = userMapper.add(user);
        int a = 1/0;
        return result;
    }
}

运行结果:

  • 在浏览器中输入对应的 URL 来访问 addUser 方法

  • 查看 user 表发现没有新增新用户信息,即事务A进行了回滚操作,与预期结果一致

调整 add 方法的事务传播机制

  • 我们将 add 方法改为  NESTED 类型的事务
  • 因为 addUser 已经创建了一个事务A,所以此处的 add 方法将会在 事务A 中创建一个嵌套事务
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
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 注解 代表该类会伴随着 项目的启动而注入到容器中
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    //    新增用户信息
    @Transactional(propagation = Propagation.NESTED)
    public int add(User user) {
        int result = userMapper.add(user);
        int a = 1/0;
        return result;
    }
}

运行结果:

  • 在浏览器中输入对应的 URL 来访问 addUser 方法
  • 此处为了验证 NESTTED 情况下,被调用方发生异常时,调用方可以 catch 其异常,这样只有子事务回滚,父事务不回滚
  • 在浏览器中输入对应的 URL 来访问 addUser 方法

  • 我们可以看到 事务A 未进行回滚操作

  • 查看 user 表发现没有新增新用户信息,即子事务进行了回滚操作,与预期结果一致

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

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

相关文章

优化您的Mac电脑风扇控制体验 - 尝试Macs Fan Control Pro!

在日常使用Mac电脑过程中&#xff0c;我们经常会遇到电脑发热的问题&#xff0c;特别是在运行大型软件或进行高负载任务时。为了保护电脑硬件&#xff0c;一个高效且可靠的风扇控制软件是必不可少的。 Macs Fan Control Pro是一款专为Mac电脑设计的风扇控制软件&#xff0c;它…

区块链技术是什么?解析其基本原理及应用

区块链技术的基本原理 在数字化时代的推动下&#xff0c;区块链技术作为一项革命性的创新&#xff0c;正逐渐渗透到各个领域&#xff0c;引领着未来科技的发展。区块链技术的基本原理大致可以总结为以下 4 点内容&#xff1a; 1. 去中心化&#xff1a;区块链是一个去中心化…

三(二)ts非基础类型(枚举)

数字枚举 使用enum定义一个枚举类型 enum Color {red,yellow,blue } let clr: Color Color.red如上面代码中&#xff0c;我们定义了一个关于颜色的枚举类型&#xff0c;里面的值会从0开始依次递增&#xff0c;也就是说Color.red为0&#xff0c;Color.yellow为1依次类推。当然…

渲染技术在虚拟仿真中的应用

虚拟仿真&#xff08;Virtual Reality&#xff09;是一种仿真技术&#xff0c;它使用计算机生成一个虚拟世界&#xff0c;用户可以通过各种传感通道与这个虚拟世界进行自然的交互。虚拟仿真技术可以创建和体验虚拟世界&#xff0c;使用户可以像在真实世界中一样进行操作和体验。…

Python - 深夜数据结构与算法之 ArrayList

目录 一.引言 二.ArrayList 介绍 1.List 2.Linked List 3.Skip List 三.经典算法实战 1.Two-Sum [1] 2.Three-Sum [15] 3.Merge-Two-Sorted-List [21] 4.Remove-Duplicates-From-Sorted-Array [26] 5.Plus-One [66] 6.Rotate-Array [189] 7. Move-Zero [283] 四.…

如何公网访问内网的群晖NAS随时随地远程访问本地存储的学习资源

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

双向链表(数据结构与算法)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

基于Java的商城网站系统设计与实现(6000字论文范例)

基于Java的商城网站系统设计与实现 姓 名&#xff1a; 刘德华 学 号&#xff1a; 指导教师&#xff1a; 2023年4月 摘要 随着我国经济活力的不断提升和互联网的快速发展&#xff0c;信息的重要性正在…

SpringIOC之ConditionEvaluator

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

如何使用cpolar+Inis在Ubuntu系统快速搭建本地博客网站公网可访问

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

安装Nacos2.2.3集群

目录 一、传统方式安装 二、Docker安装 一、传统方式安装 1、配置jdk环境 vi /etc/profile JAVA_HOME/usr/local/java JRE_HOME/usr/local/java/jre CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib PATH$JAVA_HOME/bin:$PATH export PATH JAVA_…

统筹高级前端,系统进阶精选案例实战,高效奠定前端基石

在当今的软件开发中&#xff0c;前端技术的重要性日益突出。为了应对不断变化的市场需求和用户期望&#xff0c;前端开发人员需要不断进阶&#xff0c;并掌握高级技术和系统化的实战经验。本文将介绍一些高级前端开发的精选案例&#xff0c;帮助开发者高效地奠定前端基石&#…

WRF--修改geo_em.d01.nc中的变量,保持其他信息不变

WRF–修改geo_em.d01.nc中的变量&#xff0c;保持其他信息不变 首先呢&#xff0c;找到编译WRF过程中自带的读取nc的一个fortran函数&#xff1a;read_wrf_nc.f90 可以使用Linux命令&#xff1a; find / -name read_wrf_nc.f90 找到之后&#xff0c;修改这个文件&#xff0c…

ke14--10章-1数据库JDBC介绍

注册数据库(两种方式),获取连接,通过Connection对象获取Statement对象,使用Statement执行SQL语句。操作ResultSet结果集 ,回收数据库资源. 需要语句: 1Class.forName("DriverName");2Connection conn DriverManager.getConnection(String url, String user, String…

通过异步序列化提高图表性能 Diagramming for WPF

通过异步序列化提高图表性能 2023 年 12 月 6 日 MindFusion.Diagramming for WPF 4.0.0 添加了异步加载和保存文件的功能&#xff0c;从而提高了响应能力。 MindFusion.Diagramming for WPF 提供了一个全面的工具集&#xff0c;用于创建各种图表&#xff0c;包括组织结构图、图…

华为数通---配置本地端口镜像示例(1:1)

镜像概念 定义 镜像是指将指定源的报文复制一份到目的端口。指定源被称为镜像源&#xff0c;目的端口被称为观察端口&#xff0c;复制的报文被称为镜像报文。 镜像可以在不影响设备对原始报文正常处理的情况下&#xff0c;将其复制一份&#xff0c;并通过观察端口发送给监控…

IntelliJ IDEA无公网远程连接Windows本地Mysql数据库提高开发效率

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

每日一练【查找总价格为目标值的两个商品】

一、题目描述 题目链接 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况&#xff0c;返回任一结果即可。 示例 1&#xff1a; 输入&#xff1a;price [3, 9, 12, 15], target 18 输出&#xff1a;[3,15] …

Pytorch深度强化学习1-6:详解时序差分强化学习(SARSA、Q-Learning算法)

目录 0 专栏介绍1 时序差分强化学习2 策略评估原理3 策略改进原理3.1 SARSA算法3.2 Q-Learning算法 0 专栏介绍 本专栏重点介绍强化学习技术的数学原理&#xff0c;并且采用Pytorch框架对常见的强化学习算法、案例进行实现&#xff0c;帮助读者理解并快速上手开发。同时&#…

摄像机镜头,家庭监控云台等安防监控系统镜头选型分析,低噪声,低振动,多通道

安防镜头步进驱动选用型号 GC6107 C6109 GC6209 GC6119 GC6129 GC6139 GC6208 GC6150 GC6151 GC6152 GC6125 GC6236采用5V的镜头驱动 。其中GC6107 C6109 GC6209 GC6119 GC6129 GC6139 GC6208关键特性两通道&#xff0c;256细分&#xff0c;低噪&#xff0c;内部和外部时钟…