隐蔽的事务失效...

news2025/1/16 21:00:56

🌈🌈🌈🌈🌈🌈🌈🌈
欢迎关注公众号(通过文章导读关注),发送笔记可领取 Redis、JVM 等系列完整 pdf!
【11来了】文章导读地址:点击查看文章导读!
🍁🍁🍁🍁🍁🍁🍁🍁

事务失效你了解吗?

在这里插入图片描述

事务介绍

当使用 SpringBoot 进行项目开发,如果需要使用事务的话,只需要通过在方法上添加注解 @Transactional 就可以开启该方法的事务执行

但是如果不正确地使用事务,会导致 SpringBoot 中的事务失效,如果没及时发现,可能导致严重的生产问题!

因此,在使用事务之前,需要了解事务在哪些场景下会失效,否则,如果事务失效可能会导致 数据不一致 问题的出现

事务传播类型

在学习事务失效之前,首先了解一下 事务的传播类型,在事务处理中,事务的传播类型(Propagation)是指在多个事务方法相互调用的情况下,事务如何进行传播和协调的方式。Spring 提供了多种事务传播类型,以便为不同的业务需求提供灵活的事务管理机制:

//如果有事务, 那么加入事务, 没有的话新建一个(默认)
@Transactional(propagation=Propagation.REQUIRED)
//容器不为这个方法开启事务 
@Transactional(propagation=Propagation.NOT_SUPPORTED)
//不管是否存在事务, 都创建一个新的事务, 原来的挂起, 新的执行完毕, 继续执行老的事务 
@Transactional(propagation=Propagation.REQUIRES_NEW) 
//必须在一个已有的事务中执行, 否则抛出异常
@Transactional(propagation=Propagation.MANDATORY) 
//必须在一个没有的事务中执行, 否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.NEVER) 
//如果其他bean调用这个方法, 在其他bean中声明事务, 那就用事务, 如果其他bean没有声明事务, 那就不用事务
@Transactional(propagation=Propagation.SUPPORTS) 

上边的这个是 Spring 中提供的事务的传播类型设置,还可以使用 isolation 设置底层数据库的事务隔离级别,这些就很熟悉了,在 MySQL 中就已经学过很多了:

// 读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
// 读取已提交数据(会出现不可重复读和幻读) 
@Transactional(isolation = Isolation.READ_COMMITTED)
// 可重复读(会出现幻读) MySQL默认
@Transactional(isolation = Isolation.REPEATABLE_READ)
// 串行化
@Transactional(isolation = Isolation.SERIALIZABLE)

事务失效场景

那么 Spring 是如何通过 @Transactional 为方法开启事务的呢?

底层原理就是通过 动态代理 技术,Spring 会创建一个代理对象,当执行被注解标注的方法时,是通过代理对象来执行的

在代理对象中,会在方法执行的前开启事务,并且当方法执行成功时将事务提交;如果方法抛出异常,代理对象对事务进行回滚

1.事务方法所在的类没有注册为 Spring Bean

既然需要 @Transactional 注解开启事务,那么 Spring 就需要可以扫描到这个注解,也就是 Spring 必须将 @Transactional 标注的方法所在类注册为 Spring 的 Bean,之后才可以扫描到这个注解,并且创建代理对象,如下是 错误示例

没有给 Service 添加 @Service 注解,Spring 没有管理到这个类,自然也就无法开启事务

public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void update(Goods goods) {
      // ...
    }
}

2.非 public 修饰的方法

如果一个方法被定义为 private了,那么同样事务会失效,因为在代理模式中只可以对 公共接口暴露的方法 进行代理拦截并且添加事务管理逻辑,如下是 错误示例

@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void update(Goods goods) {
      // ...
    }
}

3.同一个类中的方法互相调用

如果是在同一个类中,比如 GoodsServiceImpl 类中有两个方法 A 和 B,B 是事务方法,如果在 A 方法中直接调用 B,会导致事务失效

这是因为,A 直接去调用 B,并没有走到动态代理对象的逻辑,也就是没有被动态代理所拦截添加事务操作,事务自然就失效了,错误示例如下:

@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
    @Override
    private void A(Goods goods) {
      update(goods);
    }
  
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void update(Goods goods) {
      // ...
    }
}

4.异常被吞掉

如果在事务方法中,爆出异常,但是通过 try-catch 将异常捕捉,导致动态代理并没有感知到事务方法所出现的异常,所以事务也就没有办法回滚,导致事务失效,错误示例如下:

@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void update(Goods goods) {
        try {
          ...
        } catch (Exception e) {
            // 自定义逻辑吞掉异常
            log.error("捕获异常: {}", e);
        }
    }
}

5.多线程调用不当

对下边这个例子来说,在 A 方法中,通过多线程调用了 sendMsg() 方法,但是执行 A() 的线程和执行 sendMsg() 的线程并不是同一个线程

而 Spring 中的事务是通过 ThreadLocal 保证线程安全的,将事务和当前线程绑定,那么多个线程就会导致事务失效,如果 sendMsg() 方法执行失败了,会导致 A 方法也无法回滚

@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {
  
    @Transactional
    private void A(Goods goods) {
     new Thread(() -> {
          sendMsg();
      }).start();
    }
}
@Service
public class MessageServiceImpl{
  
    @Transactional
    private void sendMsg() {
        // ...
    }
}

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

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

相关文章

Cookie的详解使用(创建,获取,销毁)

文章目录 Cookie的详解使用&#xff08;创建&#xff0c;获取&#xff0c;销毁&#xff09;1、Cookie是什么2、cookie的常用方法3、cookie的构造和获取代码演示SetCookieServlet.javaGetCookieServlet.javaweb.xml运行结果如下 4、Cookie的销毁DestoryCookieServletweb.xml运行…

postman进阶使用

前言 对于postman的基础其实很容易上手实现&#xff0c;也有很多教程。 对于小编我来说&#xff0c;也基本可以实现开发任务。 但是今年我们的高级测试&#xff0c;搞了一下postman&#xff0c;省去很多工作&#xff0c;让我感觉很有必要学一下 这篇文章是在 高级测试工程师ht…

Python从入门到熟练

文章目录 Python 环境Python 语法与使用基础语法数据类型注释数据类型介绍字符串列表元组集合字典 类型转换标识符运算符算数运算符赋值运算符复合运算符 字符串字符串拼接字符串格式化 判断语句bool 类型语法if 语句if else 语句if elif else 语句 循环语句while循环for 循环r…

12.27重构二叉树,插入排序,队列(股票,模拟),后缀表达式求值,括号匹配,验证栈序列,选择题部分

重构二叉树 误 string in, post; struct node {char a;node* lchild, * rchild;node(char x\0) :a(x), lchild(nullptr), rchild(nullptr) {} }; void so(node* r, int il, int ir, int pl, int pr) {if (il > ir)return;int root;for (root il; root < ir; root) {if…

C++day2作业

把课上strcut的练习&#xff0c;尝试着改成class #include <iostream>using namespace std; class Stu { private:int age;string sex;int hign; public:int soce;void get_information();void set_information(); }; void Stu::set_information() {static Stu s1;cout …

C语言KR圣经笔记 5.1指针和地址 5.2指针和函数参数

第五章 指针和数组 指针是包含变量地址的变量。在 C 语言中&#xff0c;指针被大量使用&#xff0c;部分原因是有时只能用指针来表达某种计算&#xff0c;而部分原因是相比其他方式&#xff0c;指针通常能带来更紧凑和高效的代码。指针和数组是紧密关联的&#xff1b;本章也讲…

抓包工具Charles安装及使用

Charles 介绍 Charles 是在 Mac 下常用的网络封包截取工具&#xff0c;在做 移动开发时&#xff0c;我们为了调试与服务器端的网络通讯协议&#xff0c;常常需要截取网络封包来分析。 Charles 通过将自己设置成系统的网络访问代理服务器&#xff0c;使得所有的网络访问请求都…

VScode——下载、安装、配置C/C++环境(windows)

一.快速下载 还在因为vscode官方下载慢而头疼嘛&#xff0c;按这个步骤来直接起飞兄弟萌 首先进入vscode官方网站然后选择对应版本下载然后进入浏览器下载页面复制下载链接粘贴到地址栏 将地址中的/stable前换成vscode.cdn.azure.cn 即可实现超速下载 下面是一个国内镜像的下…

删除数据后, redis 内存占用还是很高怎么办?

现象&#xff1a; reids 做了数据删除&#xff0c;数据量不大&#xff0c;使用 top 命令看&#xff0c;发现还是占用大量内存 原因&#xff1a; 1.redis 底层内存根据内存分配器分配&#xff0c;不会立刻释放 2.redis 释放的内存空间不是连续的&#xff0c;存在碎片 内存碎…

DP进阶之路——整数拆分

343. 整数拆分 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36 解释…

YOLOv8训练自定义数据集和运行参数解读

1、YOLOv8深度学习环境搭建及安装 1.1. Yolov8介绍 设置操作类型 YOLOv8模型可用于各种任务&#xff0c;包括检测、分割和分类。这些任务的不同之处在于它们产生的输出类型和它们要解决的特定问题。 **检测:**检测任务涉及识别和定位图像或视频中感兴趣的对象或区域。YOLO模…

任务调度-hangfire

目录 一、Hangfire是什么&#xff1f; 二、配置服务 1.配置Hangfire服务 2.添加中间件 3.权限控制 三、配置后台任务 1.在后台中调用方法 2.调用延时方法 3.执行周期性任务 四、在客户端上配置任务 1.在AddHangfire添加UseHangfireHttpJob方法 2.创建周期任务 3.创建只读面板 总…

【《设计模式之美》】如何取舍继承与组合

文章目录 什么情况下不推荐使用继承&#xff1f;组合相比继承有哪些优势&#xff1f;使用组合、继承的时机 本文主要想了解&#xff1a; 为什么组合优于继承&#xff0c;多用组合少用继承。如何使用组合来替代继承哪些情况适用继承、组合。有哪些设计模式使用到了继承、组合。 …

腾讯云轻量应用服务器和云服务器有什么不同?

腾讯云轻量服务器和云服务器CVM该怎么选&#xff1f;不差钱选云服务器CVM&#xff0c;追求性价比选择轻量应用服务器&#xff0c;轻量真优惠呀&#xff0c;活动 https://curl.qcloud.com/oRMoSucP 轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年&#xff0c;540元三…

linux ext3/ext4文件系统(part1格式化)

ext4文件系统结构 ext3的代码已经在v4.3被删除掉了&#xff08;ARM: tegra: Rebuild default configuration on v4.3-rc1 torvalds/linux241e077 GitHub&#xff09; ext4格式化的代码可以参考e2fsprogs的实现&#xff1a;mke2fs.c 格式化后的文件系统结构如下图&#xf…

AI绘图软件,科技之旅绘画

科技与艺术的碰撞总能产生令人惊叹的火花&#xff0c;现在小编要给大家介绍一款引领未来艺术潮流的AI绘图软件——首助编辑高手。这是一款将人工智能与创意绘画完美结合的软件&#xff0c;它将为你打开一扇全新的创意之门。 所需工具&#xff1a; 一个【首助编辑高手】软件 …

mysql原理---InnoDB统计数据是如何收集的

以下聚焦于 InnoDB 存储引擎的统计数据收集策略。 1.两种不同的统计数据存储方式 InnoDB 提供了两种存储统计数据的方式&#xff1a; (1). 永久性的统计数据 这种统计数据存储在磁盘上&#xff0c;也就是服务器重启之后这些统计数据还在。 (2). 非永久性的统计数据 这种统计数…

❀My学习小记录之算法❀

目录 算法:) 一、定义 二、特征 三、基本要素 常用设计模式 常用实现方法 四、形式化算法 五、复杂度 时间复杂度 空间复杂度 六、非确定性多项式时间&#xff08;NP&#xff09; 七、实现 八、示例 求最大值算法 求最大公约数算法 九、分类 算法:) 一、定义 …

Smartbi获工信部旗下赛迪网“2023行业信息技术应用创新产品”奖

近日&#xff0c;由工信部旗下的赛迪网、《数字经济》杂志共同主办的2023行业信息技术应用创新大会上&#xff0c;“信息技术应用创新成果名单”重磅揭晓&#xff0c;思迈特软件凭借“Smartbi 自然语言分析引擎”斩获“2023行业信息技术应用创新产品”大奖。 据了解&#xff0c…

codellama模型部署(待补充)

codellama介绍 Code Llama 是一个基于Llama 2的大型代码语言模型系列&#xff0c;在开放模型、填充功能、对大输入上下文的支持以及编程任务的零样本指令跟踪能力中提供最先进的性能。我们提供多种风格来覆盖广泛的应用程序&#xff1a;基础模型 (Code Llama)、Python 专业化 …