详解mysql事务,事务并发安全问题的复现以及大事务的优化

好文推荐:
2.5万字详解23种设计模式
springboot 实现延时队列(超级实用)
2.5万字讲解DDD领域驱动设计

文章目录

  • 1. 事务定义
  • 2. 事务特性(ACID)
  • 3. 事务并发问题
  • 4. 事务隔离级别
  • 5. 基础命令
  • 6. 脏读复现
  • 7. 不可重复读复现
  • 8. 幻读复现
    • 8.1 幻读疑问
    • 8.2 MVCC
    • 8.3 快照读
    • 8.4 当前读
    • 8.5 幻读再次复现
  • 9. 大事务问题
  • 总结

在这里插入图片描述

1. 事务定义

MySQL事务是指一系列数据库操作(例如INSERT、UPDATE、DELETE等)被作为一个单独的执行单元来执行的过程。事务可以确保数据库在并发环境下的数据一致性和完整性,并支持原子性、一致性、隔离性和持久性的特性(也称为ACID特性)。

2. 事务特性(ACID)

  1. 原子性(Atomicity):事务是一个原子操作单元,要么全部执行成功,要么全部失败回滚。如果事务中的任何一个操作失败,则整个事务将被回滚到初始状态。

  2. 一致性(Consistency):事务在执行之前和执行之后,数据库的状态必须保持一致。这意味着事务将从一个一致的状态转换到另一个一致的状态,确保数据的完整性。

  3. 隔离性(Isolation):每个事务的执行都应该与其他事务相互隔离,使它们彼此独立。事务的隔离性确保并发执行的事务不会相互干扰,从而防止数据损坏或不一致。

  4. 持久性(Durability):一旦事务提交成功,其所做的更改将永久保存在数据库中,即使在系统故障或重启后也能够恢复。持久性确保事务的结果能够长期存储,以便供后续读取和使用。

3. 事务并发问题

两个事务都是读操作不会有并发问题,只有在读写或者写写场景下,就有并发问题了,后面会通过实战复现一下四种问题。

  1. 脏读:在读读场景下,一个事务读取了另一个未提交(或已回滚)事务的数据。如果读取到的数据最终不会被提交,那么本次读取就是脏读。

  2. 不可重复读:在读写(update)场景下,同一个事务内,多次读取同一行数据时,得到了不同的结果。这是由于其他事务在读取期间修改了数据造成的。

  3. 幻读:在读写(insert)场景下,一个事务读到另一个事务已提交的新插入的数据。其实这样的说法并不准确,严谨来说是在repeatable read隔离级别下,只有在当前读的情况下,才会有幻读问题,在快照读的情况下,是没有幻读问题的。什么是当前读,什么是快照读,下文会结合实例一一讲解。

  4. 更新丢失:在写写(update)场景下,两个事务同时读取同一行数据,并且同时进行修改。由于事务隔离级别的不同或执行顺序的不同,其中一个事务的修改可能会覆盖另一个事务的修改,导致更新丢失。

4. 事务隔离级别

事务隔离级别是数据库管理系统(DBMS)提供的一种机制,用于控制并发事务之间的可见性和相互影响程度。MySQL 支持四种事务隔离级别:

  1. read uncommitted:未提交读
    ①最低的隔离级别。
    ②事务可以读取其他未提交事务的未提交数据。
    ③会导致脏读、不可重复读和幻读。
  2. read committed:已提交读
    ①事务只能读取已提交事务的数据,不能读取未提交事务的数据。
    ②解决了脏读问题,但导致不可重复读和幻读。
  3. repeatable read:可重复读,MySQL默认的隔离级别。
    ①事务在开始时读取一个快照,然后在事务结束之前都使用该快照。
    ②其他事务的插入和更新会在事务结束前被阻塞。
    ③解决了脏读和不可重复读的问题,但仍存在幻读现象,幻读这里画重点,后面会讲到。
  4. serializable:序列化
    ①最高的隔离级别。
    ②所有事务按顺序执行,不允许并发,所以不建议使用,否则MySQL没有一点并发能力了
    ③提供了最强的隔离保证,完全防止脏读、不可重复读和幻读,但可能会导致性能下降,因为并发性受到限制。
事务隔离级别   		  脏读     不可重复读    幻读
read uncommitted:     否         否         否
read committed :      是         否         否
repeatable read:      是         是         否
serializable:        是         是         是

5. 基础命令

  1. 查看当前会话的事务隔离级别
SELECT @@tx_isolation;
  1. 设置当前会话的隔离级别
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
  1. 开启一个事务
BEGIN;
  1. 提交一个事务
COMMIT;
  1. 回滚一个事务
ROLLBACK;

6. 脏读复现

将事务隔离级别设置为:read uncommitted

  1. 事务A:查询数据
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level read uncommitted;
-- 开启事务
begin;  
select * from student;

查询结果:在这里插入图片描述

  1. 事务B:修改id=1的age为19,但不提交事务
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level read uncommitted;
-- 开启事务
begin;  
update student set age = 28 where id = 1;
  1. 事务A:再次查询数据,id=1的数据age改为了19,发生了脏读
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level read uncommitted;
-- 开启事务
begin;  
select * from student;

查询结果:在这里插入图片描述

  1. 解决方案:提升隔离级别为:read committed

7. 不可重复读复现

将事务隔离级别设置为:read committed,虽然解决了脏读,但是存在不可重复读

  1. 事务A:先查询数据
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level read uncommitted;
-- 开启事务
begin;  
select * from student;

查询结果:在这里插入图片描述

  1. 事务B:修改id=1的age为19,并且提交事务
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level read committed; 
-- 开启事务
begin;
update student set age = 19 where id = 1;
commit;
  1. 事务A:再次查询数据,发生了不可重复读
select @@tx_isolation; #查看当前会话的事务隔离级别
set session transaction isolation level read committed; #设置当前会话的隔离级别
begin; #开启事务
select * from student #查询数据

查询结果:在这里插入图片描述

  1. 解决方案:提升事务隔离级别:repeatable read

8. 幻读复现

将事务隔离级别设置为:repeatable read,可以解决脏读和重复读

8.1 幻读疑问

  1. 事务A:先查询数据
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level repeatable read;
-- 开启事务
begin;  
select * from student;

查询结果:在这里插入图片描述2. 事务B:插入一条数据,并提交事务

-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level repeatable read; 
-- 开启事务
begin;
INSERT INTO student (id, name, age) VALUES(3, '刘备', 38);
commit;
  1. 事务A:再次查询数据,大家可能会疑问,并没有出现事务B插入的数据,没有发生预想的幻读现象,这是为什么呢?这里就涉及到几个概念
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level repeatable read;
-- 开启事务
begin;  
select * from student;

在这里插入图片描述

8.2 MVCC

  1. MVCC(Multi-Version Concurrency Control):多版本并发控制,是一种用于处理并发事务的数据库管理系统技术。
  2. MVCC通过在数据库中维护多个版本的数据来实现事务隔离,从而允许多个事务并发执行而不会发生冲突。
  3. 用来解决数据库的并发读写的应用场景问题(一个事务在读,一个事务在写,保证数据一致性),采用无锁的方式来解决,这个是最牛逼的。
  4. MVCC主要用于支持可重复读(Repeatable Read)隔离级别,并在许多现代数据库系统中得到广泛应用,包括MySQL和PostgreSQL。

8.3 快照读

快照读是MVCC的核心特性之一。

  1. 当事务启动时,它创建一个事务快照,以捕获数据库中的当前状态。
  2. 在整个事务期间,事务只能看到在其启动时存在的数据版本。
  3. 快照读适用于可重复读(Repeatable Read)隔离级别,它确保在整个事务期间数据保持一致性。
  4. 读取一致性:事务在其整个生命周期内都会看到一个一致的数据快照,无论其他事务是否在同时进行。
  5. 无锁读取,MVCC通常不需要使用显式锁来实现事务隔离,因为每个事务都有自己的数据快照,不需要锁定其他事务正在读取的数据。
  6. 所有的select查询语句在可重复读、读已提交的隔离级别下都是快照读。

8.4 当前读

  1. 当前读是一种更加实时的读取方式。
  2. 与快照读不同,当前读不使用已存在的快照,而是始终访问数据库的最新版本。
  3. 当前读适用于读取最新数据的需求,通常用于读取而不是写入操作。
  4. 但需要注意,当前读可能会与其他事务的写操作发生冲突,因此需要格外小心以避免并发问题。
  5. 除了select操作都会触发(update,delete,insert,select…lock in share mode,select…for update)都是当前读。lock in share mode是共享锁,for update是排他锁,相关mysql各种锁的问题,关注小编后续发布文章!

8.5 幻读再次复现

  1. 事务A:当前读查询数据
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level repeatable read;
-- 开启事务
begin;  
select * from student for update;
  1. 事务B:插入一条数据
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level repeatable read; 
-- 开启事务
begin;
INSERT INTO student (id, name, age) VALUES(3, '刘备', 38);
commit;
  1. 事务A:再次查询,来了来了它来了,幻读问题出现了!!!
-- 查看当前会话的事务隔离级别
select @@tx_isolation; 
-- 设置当前会话的隔离级别
set session transaction isolation level repeatable read;
-- 开启事务
begin;  
select * from student for update;

结果如下:在这里插入图片描述

9. 大事务问题

大事务问题通常涉及对数据库中大量数据进行处理的事务,这些事务可能导致性能下降、锁冲突或事务执行时间过长。

  1. 假设有一个下单的应用场景,每当用户提交订单时,系统会执行以下操作:
    ①创建一个新订单记录
    ②从用户购物车中删除已购买的商品
    ③更新商品库存。
    现在,假设有一天,你的网站举办了一个促销活动,吸引了大量用户同时下订单。这导致了大量的 “订单处理” 事务同时运行,每个事务都要对订单和库存进行操作。

  2. 大量订单处理事务同时运行可能会导致以下问题:
    ①锁冲突:多个事务同时尝试修改相同的订单或商品库存,导致锁定和等待。
    ②性能下降:大量的数据库操作可能导致数据库性能急剧下降。
    ③事务超时:事务执行时间过长,导致超时问题。
    解决目标就是,缩短事务执行时间,提高性能

  3. 解决方法:
    ①事务拆分:
    将大事务拆分成多个小事务,每个小事务只处理一个订单或一组相关订单。
    这可以减小每个事务的范围,减少锁冲突和提高并发性。
    ②使用乐观锁:
    使用乐观锁机制来处理商品库存更新。每个事务在更新库存之前检查库存是否足够,如果不够就回滚事务。
    这可以避免大规模的锁冲突。
    ③使用消息队列:
    将订单处理任务放入消息队列,然后由后台任务异步处理。
    这将减轻数据库的压力,并允许系统在非高峰时段处理订单。
    ⑤性能优化:
    优化数据库表结构和索引以提高查询性能。
    使用数据库缓存来减少重复查询。
    ⑥定期清理历史数据:
    定期清理订单和日志数据,以减少数据库负担。

总结

  1. 我们在实际项目中,一般都会使用mysql默认的隔离级别, repeatable read可重复读
  2. 可重复读解决了事务并发安全问题的脏读,不可重复读
  3. 当前读的幻读问题MySQL是怎么解决呢,其实MySQL是通过next-key lock 临键锁来避免幻读问题的,相关mysql各种锁的问题,关注小编后续发布文章!

如果看到这里,说明你喜欢这篇文章,请关注和点赞小编。关注【微信公众号微信】搜索【老板再来一杯时光】回复【进群】即可进入无广告交流群!回复【java】即可获取【java基础经典面试】一份!

好文推荐:
2.5万字详解23种设计模式
springboot 实现延时队列(超级实用)
2.5万字讲解DDD领域驱动设计

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

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

相关文章

【快手小玩法-弹幕游戏】开发者功能测试报告提交模板

背景 快手有明确的要求,准入和准出更加严格,要求有明确的测试报告。格式如下: *本文参考字节wiki:CP侧测试报告模板(复制填写轻雀文档) 其他文章推荐:【抖音小玩法-弹幕游戏】开发者功能测试报告提交模板 一、前言…

Visual Studio编译出来的程序无法在其它电脑上运行

在其它电脑(比如Windows Server 2012)上运行Visual Studio编译出来的应用程序,结果报错:“无法启动此程序,因为计算机中丢失VCRUNTIME140.dll。尝试重新安装该程序以解决此问题。” 解决方法: 属性 -> …

10 mysql tiny/small/medium/big int 的数据存储

前言 这里主要是 由于之前的一个 datetime 存储的时间 导致的问题的衍生出来的探究 探究的主要内容为 int 类类型的存储, 浮点类类型的存储, char 类类型的存储, blob 类类型的存储, enum/json/set/bit 类类型的存储 本文主要 的相关内容是 int 类类型的相关数据的存储 …

变长参数表的用法

变长参数表是一种允许函数接受不定数量和类型的参数的机制&#xff0c;它在C语言中经常用到&#xff0c;比如printf函数。要使用变长参数表&#xff0c;你需要包含<stdarg.h>头文件&#xff0c;它定义了一些宏和类型来处理变长参数。 首先&#xff0c;你需要在函数声明中…

服务器上使用screen的学习记录

服务器上使用screen 训练模型的时候&#xff0c;花费时间是很长的&#xff0c;不可能一直挂在桌面上。所以就想到用screen了。 记录一下简单的操作指令。 创建screen screen -S roof # 新建一个名字为name的窗口&#xff0c;并进入到该窗口中进入后打开环境&#xff0c;运…

RT-Thread 时钟管理

时间是非常重要的概念&#xff0c;和朋友出去游玩需要约定时间&#xff0c;完成任务也需要花费时间&#xff0c;生活离不开时间。操作系统也一样&#xff0c;需要通过时间来规范其任务的执行&#xff0c;操作系统中最小的时间单位是时钟节拍&#xff08;OS Tick&#xff09;。 …

CloudCompare 二次开发(10)——点云投影到平面

目录 一、概述二、代码集成三、结果展示一、概述 不依赖任何第三方点云相关库,使用CloudCompare编程实现点云投影到指定平面,具体计算原理见:PCL 点云投影到拟合平面 二、代码集成 1、mainwindow.h文件public中添加: void doActionProjectToPlane(); // 投影到平面2、…

机房安全之道:构筑坚固的网络防线

引言&#xff1a; 在数字化时代&#xff0c;机房成为了许多组织和企业的核心基础设施&#xff0c;承载着重要的数据和应用。然而&#xff0c;随着网络攻击日益猖獗&#xff0c;机房的安全性显得尤为重要。本文将深入探讨如何构建坚固的网络防线&#xff0c;保护机房免受攻击的方…

Solidity 小白教程:6. 引用类型, array, struct

Solidity 小白教程&#xff1a;6. 引用类型, array, struct 这一讲&#xff0c;我们将介绍solidity中的两个重要变量类型&#xff1a;数组&#xff08;array&#xff09;和结构体&#xff08;struct&#xff09;。 数组 array 数组&#xff08;Array&#xff09;是solidity常…

STL的学习之一

1&#xff09;STL扫盲 1&#xff09;C标准库和标准模板库是不一样的 2&#xff09;标准模板库是用泛型编程方式编写的函数或者类库; 3) SGI STL linux一般用&#xff0c;P.J.Plauger STL,visual2017 windows用 STL六大组件 : 容器&#xff0c;迭代器 STL 算法(说白了就是函数…

DataX DorisWriter 插件DorisStreamLoadObserver类详细解读

DorisStreamLoadObserver 类是一个用于将数据加载到 Doris&#xff08;以前称为 Palo&#xff09;数据库中并监视加载过程的 Java 类。该类提供了一组方法&#xff0c;用于构建 HTTP 请求、处理 HTTP 响应以及监控数据加载的状态。以下是每个方法的具体作用&#xff1a; Doris…

如何使用CSS实现一个自适应等高布局?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Flexbox 布局⭐ 使用 Grid 布局⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发…

基于OpenCV+Keras+tensorflow 实现的变电站作业管控平台源代码。含人脸识别考勤,移动目标跟踪,越线检测,安全措施检测,姿态识别等功能

#综述 使用该作业现场安全生产智能管控平台来实现变电站的安全生产的智能化管理&#xff0c;通过人脸识别功能进行人员的考勤&#xff1b; 通过人员、车辆的检测和识别来实现变电站的智能化管理&#xff1b;通过安全行为识别和安全区域报警功能来实现对变电站内人员和设备安全的…

python使用字典暴力解析wifi密码

前言 最近无wifi可用,搜到了很多高质量但是没有密码的WiFi,我在想应该可以用python调用常见的wifi字典包来暴力破解一下这些WiFi,也许可以成功 原理 使用pip install pywifi命令安装pywifi 使用它调用本机网卡,设置wifi加密方式,对字典包扫描密码逐个尝试 扫描失败的密码会被…

【若依框架RuoYi-Vue-Plus 图片回显不显示问题,OSS文件上传或者本地上传】

一、问题 1.设计表 product&#xff08;商品表&#xff09; 有 id &#xff08;id&#xff09; name&#xff08;商品名&#xff09;icon&#xff08;图标&#xff09; 2.使用若依代码生成功能&#xff0c;导入product表&#xff0c;代码生成。 3.将生成的代码导入到项目中得到…

专访张少光---国内著名牛散、实战专家

导读&#xff1a;新财富最佳分析师评选作为中国本土第一份市场化的分析师评选&#xff0c;自2003年开启至今已20年&#xff0c;通过公正、公平、公开的评选&#xff0c;与市场各方共同挖掘了大量优秀分析师。值此新财富最佳分析师评选20周年之际&#xff0c;我们期望通过《对话…

51单片机智能电风扇控制系统proteus仿真设计( 仿真+程序+原理图+报告+讲解视频)

51单片机智能电风扇控制系统仿真设计( proteus仿真程序原理图报告讲解视频&#xff09; 讲解视频1.主要功能&#xff1a;2.仿真3. 原理图4. 程序代码5.设计报告6. 设计资料内容清单 51单片机智能电风扇控制系统仿真设计( proteus仿真程序原理图报告讲解视频&#xff09; 仿真图…

API管理风险:如何确保您的API安全与可靠?

API管理风险&#xff1a;如何确保您的API安全与可靠&#xff1f; 随着数字化时代的到来&#xff0c;应用程序接口&#xff08;API&#xff09;在现代软件开发中发挥着关键的作用。然而&#xff0c;API管理过程中存在着各种潜在的风险。本文将探讨如何有效地管理和缓解这些风险…

C ++ 学习之分文件 实现类

前言 当您在 C 中编写较大的程序时&#xff0c;将所有代码都放在一个文件中可能会变得混乱和不可维护。为了更好地组织代码并提高可维护性&#xff0c;您可以使用分文件实现&#xff08;Separate Compilation&#xff09;的概念。 正文 我的 circle.h 文件 #pragma once #i…

8、监测数据采集物联网应用开发步骤(6)

监测数据采集物联网应用开发步骤(5.3) 定时器插件化开发 在com.zxy.common.Com_Para.py中添加如下内容 #定时器正在运行标签 bTimeFlag False #定时器插件拦截器 TimeREFLECT_IN_CLASS "com.plugins.usereflect.testCustTimeReflectClass1" 创建自定义定时器执…