mysql 事务之LBCC与MVCC

一、事务

数据库事务(Database Transaction)是数据库管理系统(DBMS)中执行的一系列操作,这些操作被当作一个逻辑单元进行处理,以保证数据的一致性和完整性。

ACID,事务四个关键特性

1、原子性(Atomicity)

  • 原子性意味着事务中的所有操作要么全部完成,要么全部不完成。如果事务中的某个操作失败,那么整个事务应该回滚(撤销所有已经执行的操作),使数据库返回到事务开始前的状态。

2、一致性(Consistency)

  • 一致性确保事务执行前后,数据库从一个一致状态转换到另一个一致状态。事务执行过程中,必须遵守所有数据库的完整性约束(如外键约束、唯一性约束等),以确保数据的逻辑正确性。

3、隔离性(Isolation)

  • 隔离性保证多个事务并发执行时,一个事务的中间状态对其他事务是不可见的。这样,即使多个事务并发执行,每个事务都好像是在没有其他事务并发执行的情况下单独执行的。常见的隔离级别包括未提交读(Read Uncommitted)、提交读(Read Committed)、可重复读(Repeatable Read)和可串行化(Serializable)。

4、持久性(Durability)

  • 持久性意味着一旦事务提交成功,即使系统崩溃,事务对数据库的影响也是永久的。事务的修改会被持久地保存在数据库中,不会丢失。

事务隔离级别

1、读未提交(Read Uncommitted)

  • 特点:允许一个事务读取另一个事务尚未提交的数据。
  • 问题:可能导致脏读(Dirty Read),即读取到可能最终会被回滚的数据。

2、读已提交(Read Committed)

  • 特点:一个事务只能读取另一个事务已经提交的数据。
  • 问题:可能导致不可重复读(Non-repeatable Read),即同一事务中多次读取同一数据可能得到不同的结果,因为其他事务可能在此期间对数据进行了修改。

3、可重复读(Repeatable Read)

  • 特点:确保同一事务中多次读取同一数据得到相同的结果,即使其他事务在此期间对数据进行了修改。
  • 问题:可能导致幻读(Phantom Read),即一个事务在读取某些数据行后,另一个事务插入了新行,导致第一个事务在后续读取时看到了这些新行。

4、串行化(Serializable)

  • 特点:确保事务完全隔离,就像它们按某种顺序串行执行一样。
  • 问题:性能开销最大,因为事务之间不能并发执行。

数据一致性问题

脏读(Dirty Read)

  • 定义:事务A对一个值做修改,事务B读取这个值,但由于某种原因事务A回滚撤销了对这个值的修改,导致事务B读取到的值是无效数据。
  • 影响:脏读可能会导致数据不一致的问题,因为读取到的数据可能是临时性的,尚未得到持久化,也可能被后续事务回滚掉。如果其他事务依赖于这个脏读数据进行后续操作,就可能导致系统出现错误或不一致的状态。

不可重复读(Non-repeatable Read)

  • 定义:当事务A按照查询条件得到了一个结果集,这时事务B对事务A查询的结果集数据做了修改操作。之后事务A为了数据校验继续按照之前的查询条件查询,得到的结果集与前一次查询不同,导致不可重复读取原始数据。
  • 影响:不可重复读可能导致事务在多次读取数据时得到不一致的结果,从而影响事务的正确性和一致性。

幻读(Phantom Read)

  • 定义:当事务A按照查询条件得到了一个结果集,这时事务B对事务A查询的结果集数据做新增操作,之后事务A继续按照之前的查询条件查询时,结果集平白无故多了几条数据,好像出现了幻觉一样。
  • 影响:幻读可能导致事务在读取数据时得到意外的结果,因为新的数据行在事务的两次读取之间被插入到了查询范围内。

二、InnoDB

MySQL InnoDB对隔离级别的支持

事务隔离级别脏读不可重复读幻读
未提交读(未提交读)可能可能可能
已提交读(已提交)不可能可能可能
可重复读(可重复读)不可能不可能对InnoDB 不可能
串行化(Serializable)不可能不可能不可能

MySQL InnoDB 解决不可重复读和幻读

1、LBCC (Lock-Based Concurrent Control)

读锁

select * from sys_user where id = 1 for share

Concurrency: 读锁允许多个会话并发读取,但写操作会被阻塞。写锁会阻塞其他读操作和写操作。

写锁

-- 获取行级写锁
SELECT * FROM sys_user WHERE id = 1 FOR UPDATE;

根据算法,写锁可以细分为

  • 记录锁(Record Lock)
    记录锁是锁定单个行记录的锁,防止其他事务对此行进行update和delete等修改操作。
SELECT * FROM sys_user WHERE id = 1 FOR UPDATE;

上述语句会在 sys_user 表中,锁定 id 为 1 的那一行。

  • 间隙锁 (Gap Lock)
    当进行范围查询时,没有命中记录的时候会使用间隙锁,只对添加有效,允许修改不存在的值,既只对insert有效,update无效
    间隙锁只锁定记录之间的间隙,而不锁定任何实际的记录。间隙锁用于防止其他事务在锁定的间隙中插入新记录。相同间隙锁之间不冲突

假设一个表的数据为
在这里插入图片描述

1、设置隔离级别为 REPEATABLE READ:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

2、开启事务并执行范围查询
间隙锁会锁住最后一个 key 的下一个左开右闭的区间,没有key就锁住无穷,防止幻读

START TRANSACTION;
-- 这条语句会锁定 id 在 10 和 20 之间的所有记录和间隙,锁住的是闭区间(10,20) 系统不存在数据
SELECT * FROM sys_menu_perm WHERE id <= 4 FOR UPDATE;-- 提交第一个事务后,再次尝试插入,可以成功
COMMIT;

3、在另一个事务中尝试插入(应被阻塞):

-- 另一个会话/事务中
START TRANSACTION;-- 试图插入一条记录到被锁定的间隙中
INSERT INTO sys_menu_perm (id, role_id) VALUES (5, 12);  -- 被阻塞
update `saas`.sys_menu_perm set role_id = 5 where id = 8;  -- 被阻塞
INSERT INTO sys_menu_perm (id, role_id) VALUES (7, 12);  -- 不被阻塞
COMMIT;
  • 临键锁(Next-Key Lock)
    当我们使用了范围查询,不仅仅命中了Record 记录,还包含了 Gap间隙,在这种情况下我们使用的就是临键锁
    临键锁是 MySQL 里面默认的行锁算法,相当于记录锁加上间隙锁。
    临键锁不仅锁定了记录本身,还锁定了记录和前一条记录之间的间隙。这意味着它锁定了索引记录范围内的所有可能插入的位置。

假设有一个表的记录
在这里插入图片描述

1、设置隔离级别为 REPEATABLE READ:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
开启事务并执行范围查询(获取临键锁):

2、查询并锁定 id 在 2 和 5 之间的记录和间隙
临键锁,锁住最后一个 key 的下一个左开右闭的区间,没有key就锁住无穷,防止幻读

START TRANSACTION;SELECT * FROM employees WHERE id >= 2 AND id <= 11 FOR UPDATE; -- 验证插入是否被阻塞(在另一个事务中尝试插入):
左开右闭的区间,会锁住 2,(2,5],(5,9], (9,11],(11,15] -- 临键锁,锁住最后一个 key 的下一个左开右闭的区间。防止幻读-- 提交第一个事务后,再次尝试插入,可以成功
COMMIT;

3、验证插入是否被阻塞(在另一个事务中尝试插入)

-- 在另一个会话/事务中
START TRANSACTION;
-- 试图在已经锁定的间隙中插入新记录
INSERT INTO sys_menu_perm (id, role_id) VALUES (10, 12);  -- 被阻塞INSERT INTO sys_menu_perm (id, role_id) VALUES (16, 12);  -- 不被阻塞-- 试图在已经锁定的间隙中更新记录
update `saas`.sys_menu_perm set role_id = 15 where id = 15;  -- 被阻塞COMMIT;

注意:

  • 1、在读已提交(READ COMMITTED)隔离级别下,InnoDB 只会使用记录锁,不会应用间隙锁和临键锁。
  • 2、不使用索引的话会锁住全表
  • 3、在非唯一索引情况下,使用等值查询的时候,也会锁住下一个间隙,所有索引情况下,范围查询都会锁住下一个左开右闭的间隙
    例如表数据如下
    在这里插入图片描述

唯一索引

事务一:
START TRANSACTION;
-- 这条语句会锁定 id 在 8 和 (8,10] 的记录和间隙
SELECT * FROM `saas`.sys_menu_perm WHERE id = 8 FOR UPDATE;commit;事务二:
START TRANSACTION;
INSERT INTO `saas`.sys_menu_perm (id, role_id) VALUES (9, 9);  -- 不会被阻塞
commit;

非唯一索引

事务一:
START TRANSACTION;
-- 这条语句会锁定 id = 8 的记录
SELECT * FROM `saas`.sys_menu_perm WHERE role_id = 8 FOR UPDATE;commit;事务二:
START TRANSACTION;
INSERT INTO `saas`.sys_menu_perm (id, role_id) VALUES (9, 9);  -- 会被阻塞
commit;

原理
在这里插入图片描述

2、MVCC(Multi-Version Concurrency Control)

核心组件
1、版本链(Version Chain)

InnoDB通过为每行记录保存多个版本的快照来实现MVCC。这些版本通过隐式生成的列来管理,包括:

  • m_ids:Read View 创建时未提交的活跃事务 ID 列表。m_ids 不包括当前事务自己和已提交的事务(正在内存中)。

  • m_creator_trx_id:创建该 Read View 的事务 ID。

  • m_low_limit_id(max_trx_id):目前出现过的最大的事务 ID+1,即下一个将被分配的事务 ID。

  • m_up_limit_id(min_trx_id): m_ids 中最小的事务 ID,如果 m_ids 为空,则 m_low_limit_id为m_up_limit_id

2、隐藏字段:

  • DB_TRX_ID:6字节,记录最近修改(修改/插入)该记录的事务ID。
  • DB_ROLL_PTR:7字节,回滚指针,指向该记录的上一个版本(存储于rollback segment里),用于配合undo日志
  • DB_ROW_ID:6字节,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引。

3、undo日志:

  • insert undo log:事务在insert新记录时产生的undo日志,只在事务回滚时需要,并且在事务提交后可以被立即丢弃。
  • update undo log:事务在进行update或delete时产生的undo日志,不仅在事务回滚时需要,在快照读时也需要,所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除。

4、Read View:

  • 事务进行快照读操作时生成的读视图,在该事务执行快照读的那一刻,会生成数据库系统当前的一个版本视图,RR级别的Read View保持不变

Read View 可见性具体判断如下:

  • DB_TRX_ID == m_creator_trx_id ,表示当前事务访问自己的记录。
  • DB_TRX_ID < m_up_limit_id,说明生成该版本的事务在当前事务生成 Read View 之前已经提交,因此该版本可以被当前事务访问。
  • DB_TRX_ID >= m_low_limit_id ,说明生成该版本的事务在当前事务生成 Read View 之后才提交,因此该版本不能被当前事务访问。
  • m_low_limit_id > DB_TRX_ID >= m_up_limit_id ,检查 DB_TRX_ID 在m_ids 列表中,事务仍处于活跃状态,因此该版本不能被访问;如果不在列表中,说明在创建 Read View 时生成该版本的事务已经提交,因此该版本可以被访问。

快照读与当前读
1、快照读:

  • 不加锁的select操作就是快照读,即不加锁的非阻塞读。
  • 快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。
  • 快照读的实现基于多版本并发控制,即MVCC,它避免了加锁操作,降低了开销。
  • 快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本。

2、当前读:

  • 像select lock in share mode(共享锁)、select for update、update、insert、delete(排他锁)这些操作都是一种当前读。
  • 当前读读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

示例
表sys_menu_perm的数据如下
在这里插入图片描述
在各个时间段事务1、2 、3分别执行查询更新插入操作
在这里插入图片描述

分析:
T1 的 read view 为

字段
m_ids[T1]
m_low_limit_idT2
m_up_limit_idT1
m_creator_trx_idT1

T3 的 read view 为

字段
m_ids[T1,T3]
m_low_limit_idT4
m_up_limit_idT1
m_creator_trx_idT3

对于 Time 5 时刻,版本链数据为
在这里插入图片描述

对于事务T1,判断规则如下

  • ID = 6
    链路第一条数据,DB_TRX_ID不存在,即为数据库的原始数据,可以访问的记录。

  • ID = 8
    链路第一条数据,DB_TRX_ID = T2 ,DB_TRX_ID >= m_low_limit_id ,说明生成该版本的事务在当前事务生成 Read View 之后才提交,因此该版本不能被当前事务访问。
    链路第二条数据,DB_TRX_ID不存在,即为数据库的原始数据,可以访问的记录。

对于事务T3,判断规则如下

  • ID = 6
    链路第一条数据,DB_TRX_ID不存在,即为数据库的原始数据,可以访问的记录。
  • ID = 8
    链路第一条数据,DB_TRX_ID = T2,m_low_limit_id > DB_TRX_ID >= m_up_limit_id ,检查 DB_TRX_ID 不在 m_ids 列表中,说明在创建 T3 的 Read View 时生成该版本的事务已经提交,因此该版本可以被访问。

对于 Time 9 时刻,版本链数据为
在这里插入图片描述
对于事务T1,判断规则如下

  • ID = 2
    链路第一条数据,DB_TRX_ID = T3,DB_TRX_ID >= m_low_limit_id,说明生成该版本的事务在当前事务生成 Read View 之后才提交,因此该版本不能被当前事务访问。

  • ID = 6
    链路第一条数据,DB_TRX_ID不存在,即为数据库的原始数据,可以访问的记录。

  • ID = 8
    链路第一条数据,DB_TRX_ID = T1 ,DB_TRX_ID == m_creator_trx_id ,表示当前事务访问自己的记录。

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

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

相关文章

Wireshark 4.4.2:安全更新、错误修复、更新协议支持

流行的网络协议分析器Wireshark已更新至4.4.2版本。它可用于网络故障排除、分析、开发和教育。 已修复以下漏洞&#xff1a; wnpa-sec-2024-14 FiveCo RAP 解剖器无限循环。wnpa-sec-2024-15 ECMP 解析器崩溃。 更新的协议支持&#xff1a; ARTNET、ASN.1 PER、BACapp、B…

Vue-01

Vue框架 Vue官网&#xff1a; Vue.js 框架 数据模型和view的通信就是依靠viewmodel的关键。 目前主流版本仍然是vue2版本。 Vue快速入门 1.新建一个HTML文件&#xff0c;引入Vue.js文件。Vue.js文件是官方引入的一个文件&#xff0c;我们如果要使用Vue就必须引入这个文件。…

HarmonyOS 5.0应用开发——列表(List)

【高心星出品】 文章目录 列表&#xff08;List&#xff09;列表介绍列表布局设置主轴方向设置交叉轴方向 列表填充分组列表填充 滚动条位置设置滚动位置滚到监听 列表项侧滑 列表&#xff08;List&#xff09; 列表介绍 列表作为一种容器&#xff0c;会自动按其滚动方向排列…

004 MATLAB数值微积分

01 函数的极值点 求解一元函数在区间(x1,x2)中极小值点&#xff1a; xfminbnd(fun,x1,x2)求解初始向量为x0的多元函数极小值点x和对应的极值y [x,y]fminsearch(fun,x0)02 微积分 1.数值微分&#xff1a; 一次微分&#xff1a; diff(x) 若x是一个向量&#xff0c;则返回[x(…

Milvus×Florence:一文读懂如何构建多任务视觉模型

近两年来多任务学习&#xff08;Multi-task learning&#xff09;正取代传统的单任务学习&#xff08;single-task learning&#xff09;&#xff0c;逐渐成为人工智能领域的主流研究方向。其原因在于&#xff0c;多任务学习可以让我们以最少的人力投入&#xff0c;获得尽可能多…

开展网络安全成熟度评估:业务分析师的工具和技术

想象一下,您坐在飞机驾驶舱内。起飞前,您需要确保所有系统(从发动机到导航工具)均正常运行。现在,将您的业务视为飞机,将网络安全视为飞行前必须检查的系统。就像飞行员依赖检查表一样,业务分析师使用网络安全成熟度评估来评估组织对网络威胁的准备程度。这些评估可帮助…

MATLAB 中有关figure图表绘制函数设计(论文中常用)

在撰写论文时&#xff0c;使用 MATLAB 导出的图像常常因大小和格式不统一&#xff0c;导致投稿时编辑部频繁退稿&#xff0c;要求修改和调整。这不仅浪费时间&#xff0c;也增加了工作量。为了减少这些麻烦&#xff0c;可以在 MATLAB 中导出图像时提前设置好图表的大小、格式和…

Nuxt.js 应用中的 render:response 事件钩子

title: Nuxt.js 应用中的 render:response 事件钩子 date: 2024/11/29 updated: 2024/11/29 author: cmdragon excerpt: render:response 是一个在 Nuxt.js 中与服务器端渲染(SSR)相关的钩子,它会在请求的响应发送之前被调用。这个钩子的目的是让开发者可以在响应发送之…

AI实践项目——图片视频自动上色系统,让旧照片焕然一新

1.主要内容 &#xff08;1&#xff09;项目概述 在图片处理的世界中&#xff0c;AI不仅用于识别和分析&#xff0c;还可以赋予灰度照片色彩&#xff0c;为其注入新的生命。今天&#xff0c;我们将探讨一种通过深度学习模型为灰度图片上色的技术。 ①参考文献 Colorful Image…

Vue教程|搭建vue项目|Vue-CLI新版脚手架

一、安装Node环境 安装Node及Npm环境 Node下载地址:Node.js — Run JavaScript EverywhereNode.js is a JavaScript runtime built on Chromes V8 JavaScript engine.https://nodejs.org/en/ 安装完成后,检查安装是否成功,并检查版本,命令如下: node -v npm -v mac@Macd…

从 App Search 到 Elasticsearch — 挖掘搜索的未来

作者&#xff1a;来自 Elastic Nick Chow App Search 将在 9.0 版本中停用&#xff0c;但 Elasticsearch 拥有你构建强大的 AI 搜索体验所需的一切。以下是你需要了解的内容。 生成式人工智能的最新进展正在改变用户行为&#xff0c;激励开发人员创造更具活力、更直观、更引人入…

ERROR in [eslint] Invalid Options ‘extensions‘ has been removed.

看着这个报错 感觉是版本不对引起的 ERROR in [eslint] Invalid Options: - Unknown options: extensions - extensions has been removed. ERROR in Error: Child compilation failed: [eslint] Invalid Options: - Unknown options: extensions - extensions has b…

架构-微服务-服务调用Dubbo

文章目录 前言一、Dubbo介绍1. 什么是Dubbo 二、实现1. 提供统一业务api2. 提供服务提供者3. 提供服务消费者 前言 服务调用方案--Dubbo‌ 基于 Java 的高性能 RPC分布式服务框架&#xff0c;致力于提供高性能和透明化的 RPC远程服务调用方案&#xff0c;以及SOA服务治理方案。…

使用Grafana K6来测测你的系统负载能力

背景 近期我们有个号称会有很高很高并发的系统要上线&#xff0c;为了测试一下自己开发的系统的负载能力&#xff0c;准备了点海克斯科技&#xff0c;来看看抗不抗的住。 之前笔者写过用Apache JMeter进行压力测试的文章&#xff08;传送门&#x1f449;&#xff1a;https://…

气膜建筑:打造全天候安全作业空间,提升工程建设效率—轻空间

在现代建筑工程中&#xff0c;施工环境的管理和作业效率是决定项目进度和质量的关键因素。然而&#xff0c;施工过程中常常会受到天气变化的影响&#xff0c;诸如大风、雨雪、沙尘等恶劣天气常常延误工期&#xff0c;增加施工难度。为了解决这一问题&#xff0c;气膜建筑以其独…

CTF-Hub SQL 报错注入(纯手动注入)

​ 当输入1时&#xff0c;发现只有查询正确&#xff0c;基本上可以判断出没有回显 开始注入(工具hackerBar) 题目是报错注入&#xff0c;方向就比较明显&#xff0c;大致说一下用到的函数和原理。 常见报错注入函数&#xff1a; 通过 floor() 报错注入通过 extractValue() …

HCIE:详解OSPF,从基础到高级特性再到深入研究

目录 前言 一、OSPF协议基本原理 简介 基本原理 OSPF路由器类型 OSPF网络类型 OSPF报文类型和封装 OSPF邻居的建立的维护 DR和BDR的选举 伪节点 LSDB的更新 OSPF的配置 二、OSPF的高级特性 虚连接&#xff08;Virtual-Link&#xff09; OSPF的LSA和路由选择 OSPF…

C++游戏开发入门:如何从零开始实现自己的游戏项目?

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C游戏开发的相关内容&#xff01; 关于【…

直接抄作业!Air780E模组LuatOS开发:位运算(bit)示例

在嵌入式开发中&#xff0c;位运算是一种高效且常用的操作技巧。本文将介绍如何使用Air780E模组和LuatOS进行位运算&#xff0c;并通过示例代码帮助读者快速上手。 一、位运算概述 位运算是一种在计算机系统中对二进制数位进行操作的运算。由于计算机内部数据的存储和处理都是…

linux centos nginx编译安装

编译安装nginx&#xff08;Centos&#xff09; 编译需要的基础环境yum -y install pcre-devel openssl openssl-devel gd-devel gcc gcc-c1.下载nginx源码包 Nginx源码包下载地址&#xff1a;nginx源码包下载 2. 上传nginx源码包到服务器 我上传的地址是/home/chenhao/nginx…