MYSQL实现原理 - 事务的隔离级别
版本
| 版本 | 日期 | 说明 |
| v1 | 2025-02-10 |
准备
为后续故事的顺利展开,这里创建一个账户表
create database test;CREATE TABLE `test`.`account` (`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',`user_name` varchar(200) NOT NULL DEFAULT '' COMMENT '用户名称',`amount` int unsigned NOT NULL DEFAULT 0 COMMENT '金额',`created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账户表';
事务
MySQL事务是数据库管理系统执行过程中的一个逻辑单位,它由一组在数据库中执行的操作构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位
示例
账户1和账户2进行100元交易
-- 开启事务
begin;-- 账户1向账户2转100元
update test.account set amount = amount- 100 where user_id = 1 and amount > 100;update test.account set amount = amount + 100 where user_id = 2;-- 提交事务
commit ;
ACID特性
- 原子性(Atomicity):事务是一个原子操作单元,事务中的操作要么全部成功执行,要么全部失败回滚,以保证数据库状态的完整性。
- 一致性(Consistency):事务的执行必须使数据库从一个一致状态转换到另一个一致状态,满足所有业务规则和约束条件。
- 隔离性(Isolation):并发事务的执行不能相互干扰,每个事务在逻辑上都是独立的,以保证数据并发访问的正确性。
- 持久性(Durability):一旦事务提交成功,其对数据库所做的更改就是永久性的,即使系统发生故障也能恢复。
理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大,我们肯定希望能最大可能的并行处理更多的事务,那么事务并发执行会引入哪些问题呐?
事务并发执行会遇到的问题
脏写(Dirty Write)
| 发生时间编号 | Session A | Session B |
|---|---|---|
| 1 | begin; | |
| 2 | begin; | |
| 3 | update test.account set amount = 100 where user_id = 2; | |
| 4 | update test.account set amount = 200 where user_id = 2; | |
| 5 | commit ; | |
| 6 | rollback ; |
脏读(Dirty Read)
| 发生时间编号 | Session A | Session B |
|---|---|---|
| 1 | begin; | |
| 2 | begin; | |
| 3 | update test.account set amount = 300 where user_id = 2; | |
| 4 | select amount from test.account where user_id = 2; 如果读到了amount = 300 则说明读到了脏读 | |
| 5 | commit ; | |
| 6 | rollback ; |
不可重复度(Non-Repeatable Read)
| 发生时间编号 | Session A | Session B |
|---|---|---|
| 1 | begin; | |
| 2 | select amount from test.account where user_id = 2; 此时读到的 amount 值为 100 | |
| 3 | update test.account set amount = 300 where user_id = 2; | |
| 4 | select amount from test.account where user_id = 2; 如果此时读到的 amount 值为 300 ,说明发生了不可重复读 | |
| 5 | update test.account set amount = 400 where user_id = 2; | |
| 6 | select amount from test.account where user_id = 2; 如果此时读到的 amount 值为 400 ,说明发生了不可重复读 |
幻读(Phantom)
| 发生时间编号 | Session A | Session B |
|---|---|---|
| 1 | begin; | |
| 2 | select count(*) from test.account where user_id > 0; 假设此时读到的数量为100 | |
| 3 | insert into test.account (user_name, amount) values ("张三", 0); | |
| 4 | select count(*) from test.account where user_id > 0; 如果此时读到的数量为101,说明发生了幻读 |
如上图,在Session A中开启事务后,进行一次查询,会返回此时的数据数量,之后通过Session B插入数据,然后再 通过 Session A 进行一次查询,如果次数读取到的数量包含了 Session B插入的数据,说明发生了幻读
有的同学就会疑惑了,在 Session A 的事务中,Session B新增了数据会导致幻读现象,那么如果删除了数据呐,是不是也算幻读呐?这里需要明确的是这种现象不叫幻读,幻读强调的是在一个事务中相同条件下多次读取,后者读到了前者没有读到的数据,针对的是新增记录情况。如果针对数据进行了删除操作,这是对每一条被删除的数据都发生了不可重复读现象
事务的隔离级别
以上几个事务并发问题按照严重程度来排序,是以下顺序:
脏写 > 脏读 > 不可重复读 > 幻读
针对事务并发执行遇到的这些问题,结合使用场景,舍弃部分隔离性,在sql标准中添加了四种隔离级别:
- READ UNCOMMITTED :未提交读。
- READ COMMITTED :已提交读。
- REPEATABLE READ :可重复读。
- SERIALIZABLE :可串行化。
隔离级别与事务并发问题可发生情况,具体如下:
| 隔离级别 | 脏写 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|---|
| READ UNCOMMITTED | F | T | T | T |
| READ COMMITTED | F | F | T | T |
| REPEATABLE READ | F | F | F | T |
| SERIALIZABLE | F | F | F | F |
- READ UNCOMMITTED 隔离级别下,可能发生 脏读 、 不可重复读 和 幻读 问题。
- READ COMMITTED 隔离级别下,可能发生 不可重复读 和 幻读 问题。
- REPEATABLE READ 隔离级别下,可能发生 幻读 问题。
- SERIALIZABLE 隔离级别下,各种问题都不可以发生。
如何设置事务的隔离级别
通过SQL语句设置
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;其中的 level 可选值有4个:level: {REPEATABLE READ| READ COMMITTED| READ UNCOMMITTED| SERIALIZABLE
} GLOBAL、SESSION
这两个关键字可以对不同范围的事务产生不同的影响,也可以为空
GLOBAL
全局范围影响
用法:
SET GLOBAL TRANSACTION ISOLATION LEVEL level; 影响范围:
- 只对执行完该语句之后产生的会话起作用
- 当前已经存在的会话无效
SESSION
会话范围影响
用法:
SET SESSION TRANSACTION ISOLATION LEVEL level;
影响范围:
- 对当前会话的所有后续的事务有效
- 该语句可以在已经开启的事务中间执行,但不会影响当前正在执行的事务
- 如果在事务之间执行,则对后续的事务有效
无关键词
只对执行语句的下一个事务产生影响
用法:
SET TRANSACTION ISOLATION LEVEL level; 影响范围:
- 对当前会话的下一个将开启的事务有效
- 下一个事务执行完,后续的事务将恢复默认隔离级别
- 该语句不能在已开启的事务中执行,会报错
mysql> begin;
Query OK, 0 rows affected (0.00 sec)mysql> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ERROR 1568 (25001): Transaction characteristics can't be changed while a transaction is in progress
mysql> 服务器启动时设置
可以通过修改启动参数 transaction-isolation 的值 来修改mysql服务器的默认隔离级别。
比如启动时添加如下参数设置,那么MYSQL的默认隔离级别隔离级别就会从原来的
--transaction-isolation=SERIALIZABLE 通过设置系统变量修改
可以通过修改系统变量transaction_isolation的方式来设置事务的隔离级别,详情见:
https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_transaction_isolation
查看当前会话的默认隔离级别
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.02 sec)mysql> 或者
mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)mysql> Innodb 不同事务隔离级别的实现方式
读未提交(Read Uncommitted)
- 在这种隔离级别下,
SELECT语句不会加锁,因此可能会读取到未提交事务修改的数据,即“读脏”。 - 这是并发性最高但一致性最差的隔离级别,因为它允许读取到其他事务尚未提交的数据
串行化(Serializable)
- 在这种隔离级别下,所有的
SELECT语句都会被隐式地转化为SELECT ... IN SHARE MODE,这意味着如果有未提交的事务正在修改某些行,那么所有读取这些行的SELECT语句都会被阻塞。 - 这是一致性最好的隔离级别,但并发性最差,因为它将事务完全串行化,从而避免了所有并发问题。
- 在这种隔离级别下,
UPDATE和DELETE操作也会与其他事务互斥,即同一时间只能有一个事务对这些数据进行修改。
可重复读(Repeated Read, RR)
- 这是InnoDB的默认隔离级别。
- 在这种隔离级别下,普通的
SELECT语句使用快照读(snapshot read),这是一种不加锁的一致性读,底层使用MVCC来实现。 - 加锁的
SELECT(如SELECT ... IN SHARE MODE或SELECT ... FOR UPDATE)、UPDATE和DELETE等语句的锁策略取决于查询条件:- 如果在唯一索引上使用唯一的查询条件,那么会使用记录锁(record lock),而不会封锁记录之间的间隔。
- 如果使用范围查询条件,那么会使用间隙锁(gap lock)和临键锁(next-key lock),以锁住索引记录之间的范围,避免范围间插入记录,从而避免产生幻影行记录和不可重复的读。
读提交(Read Committed, RC)
- 这是互联网最常用的隔离级别。
- 在这种隔离级别下,普通的
SELECT语句也是快照读,但加锁的SELECT、UPDATE和DELETE等语句的锁策略与可重复读有所不同:- 除了在外键约束检查和重复键检查时会封锁区间外,其他时刻都只使用记录锁。
- 这意味着其他事务的插入操作仍然可以执行,因此可能会导致读取到幻影记录。
总结
本篇讲述了引入事务隔离级别的原因,及事务隔离级别的查看和设置方式,事务隔离级别的底层实现逻辑描述需要更长篇幅,这里先做简述,后续会逐块展开讲解
相关文章:
MYSQL实现原理 - 事务的隔离级别
版本 版本日期说明v12025-02-10 准备 为后续故事的顺利展开,这里创建一个账户表 create database test;CREATE TABLE test.account (user_id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 用户ID,user_name varchar(200) NOT NULL DEFAULT COMMENT 用户名…...
如何在Kickstart自动化安装完成后ISO内拷贝文件到新系统或者执行命令
如何在Kickstart自动化安装完成后ISO内拷贝文件到新系统或者执行命令 需求 在自动化安装操作系统完成后,需要对操作系统进行配置需要拷贝一些文件到新的操作系统中需要运行一些脚本 问题分析 Linux安装操作系统时,实际上是将ISO镜像文件中的操作系统…...
PHP 调用 SiliconFlow 语音生成 API 的脚本,用于将文本转换为 MP3 格式的语音文件
脚本概述 PHP 调用 SiliconFlow 语音生成 API 的脚本,用于将文本转换为 MP3 格式的语音文件。 代码结构 依赖引入 require_once vendor/autoload.php; use OpenAI\Client;使用 Composer 的自动加载机制引入 OpenAI PHP 客户端库 文件路径处理 $speechFilePath…...
具身智能训练新思路!将生成视频用于训练机器人
将生成视频用于训练具身智能(Embodied AI)确实是近年来备受关注的前沿方向,这一思路通过结合生成式AI(如扩散模型、神经辐射场等)与机器人学习,为解决真实世界数据稀缺、训练成本高等问题提供了新可能。以下从技术逻辑、潜在优势、挑战及案例方向展开分析: 一、技术逻辑…...
MindStudio制作MindSpore TBE算子(四)算子测试(ST测试-Ascend910B/ModelArts)--失败尝试
上一节,MindStudio制作MindSpore TBE算子(三)算子测试(ST测试),因此缺乏对应的硬件环境导致无法进行ST测试,导致难以自安,今天搞来Ascend910B服务器来填坑,看看是否是硬件…...
transformer 基础知识
概要:简要记录 Encoder-Decoder 架构、seq2seq 模型、Attention 机制 Encoder & Decoder encoder 接收输入,生成一个固定长度的上下文向量(编码器生成的最终隐藏状态);decoder 接收上下文向量(或状态…...
基于 STM32 的病房监控系统
标题:基于 STM32 的病房监控系统 内容:1.摘要 基于 STM32 的病房监控系统摘要:本系统采用 STM32 微控制器作为核心,通过传感器实时监测病房内的环境参数,如温度、湿度、光照等,并将数据上传至云端服务器。医护人员可以通过手机或…...
DeepSeek底层揭秘——知识图谱与语料库的联邦学习架构
目录 1. 知识图谱与语料库的联邦学习架构 2. 技术要素 3. 技术难点与挑战 4. 技术路径 5. 应用场景 6. 最新研究与技术进展 7. 未来趋势 8. 实际案例 猫哥说 1. 知识图谱与语料库的联邦学习架构 (1) 定义 “知识图谱与语料库的联邦学习架构”是一种结合知识图谱&…...
C++--iomanip库
目录 1. 设置字段宽度:std::setw() 2. 设置浮点数精度:std::setprecision() 3. 设置填充字符:std::setfill() 4. 控制对齐方式:std::left 和 std::right,std::internal 5. 控制进制输出:std::hex、std…...
机器学习(李宏毅)——self-Attention
一、前言 本文章作为学习2023年《李宏毅机器学习课程》的笔记,感谢台湾大学李宏毅教授的课程,respect!!! 二、大纲 何为self-Attention?原理剖析self-Attention VS CNN、RNN、GNN 三、何为self-Attenti…...
Android和DLT日志系统
1 Linux Android日志系统 1.1 内核logger机制 drivers/staging/android/logger.c static size_t logger_offset( struct logger_log *log, size_t n) { return n & (log->size - 1); } 写的off存在logger_log中(即内核内存buffer)&am…...
实现限制同一个账号最多只能在3个客户端(有电脑、手机等)登录(附关键源码)
如上图,我的百度网盘已登录设备列表,有一个手机,2个windows客户端。手机设备有型号、最后登录时间、IP等。windows客户端信息有最后登录时间、操作系统类型、IP地址等。这些具体是如何实现的?下面分别给出android APP中采集手机信…...
DeepAR:一种用于时间序列预测的深度学习模型
介绍 DeepAR是一种基于递归神经网络(RNN)的时间序列预测模型,由亚马逊在2017年提出。它特别适用于处理多变量时间序列数据,并能够生成概率预测。DeepAR通过联合训练多个相关时间序列来提高预测性能,从而在实际应用中表…...
伺服报警的含义
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在开发C#的运动控制程序的时候,一个必要的步骤就是设置伺服报警信号的…...
Linux | 文件描述符
文章目录 Linux | 文件描述符1. 文件描述符概述2. 与文件描述符关联的数据结构2.1 进程级的文件描述符表(struct files_struct)2.2 文件描述符表项(struct fdtable)2.3 文件对象(struct file)2.4 索引节点&…...
蓝桥杯-洛谷刷题-day5(C++)(为未完成)
1.P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布 i.题目 ii.代码 #include <iostream> #include <string> using namespace std;int N, Na, Nb; //0-"剪刀", 1-"石头", 2-"布", 3-"蜥", 4-"斯"࿱…...
LVS 负载均衡集群(NAT模式)
一、环境准备 四台主机(一台 LVS、两台 RS、一台客户端) 1.1.LVS 主机 LVS 主机(两块网卡) 第一块:NAT模式(内网) 第二块:添加网卡(仅主机模式)࿰…...
开源的轻量级分布式文件系统FastDFS
FastDFS 是一个开源的轻量级分布式文件系统,专为高性能的分布式文件存储设计,主要用于解决海量文件的存储、同步和访问问题。它特别适合以中小文件(如图片、视频等)为载体的在线服务,例如相册网站、视频网站等。 FastD…...
解决 DeepSeek 官网服务器繁忙的实用方案
解决 DeepSeek 官网服务器繁忙的实用方案 大家在使用 DeepSeek 时,是不是经常遇到官网服务器繁忙,等半天都加载不出来的情况?别担心,今天就给大家分享一个用 DeepSeek 硅基流动 Cherry Studio 解决这个问题的实用方案ÿ…...
Terraform 最佳实践:Top 10 常见 DevOps/SRE 面试问题及答案
1. 如何高效管理 Terraform 状态? 使用远程后端,如 S3 或 GCS,存储 Terraform 状态文件。这可以支持协作并确保团队工作时状态的一致性。使用 DynamoDB 或 GCS 锁定状态以防止同时修改状态。 示例: backend "s3" {bu…...
嵌入式八股文面试题(二)C语言算法
相关概念请查看文章:C语言概念。 1. 如何实现一个简单的内存池? 简单实现: #include <stdio.h> #include <stdlib.h>//内存块 typedef struct MemoryBlock {void *data; // 内存块起始地址struct MemoryBlock *next; // 下一个内…...
#渗透测试#批量漏洞挖掘#LiveBos UploadFile 任意文件上传漏洞
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章读。 目录 漏洞背景 漏洞成因 影响评估 检测方案 …...
ds-download-link 插件:以独特图标选择,打造文章下载链接
源码介绍 “ds-download-link”插件为 WordPress 网站提供了在文章编辑器中添加下载链接的功能,每个下载链接都支持图标选择,并能将这些链接以美观的样式展示在文章前端页面。以下是该插件的主要特性和功能: 后台功能 在文章编辑器下方添加…...
介绍下SpringBoot在分布式架构中,如何实现读写分离
在分布式架构中,Spring Boot 可以通过多种方式实现读写分离,以提升系统性能和扩展性。以下是常见的实现方法: 1. 使用多数据源 通过配置多个数据源,将读操作和写操作分别路由到不同的数据库实例。 实现步骤: 配置多…...
判断函数是否为react组件或lazy包裹的组件
function Modal(){return <p>123</p> } 实参里填入函数名,是false 实参里填入标签形式的函数,是true isValidElement(Modal)//false isValidElement(<Modal></Modal>)//true 官方说明 isValidElement – React 中文文档 但是官方并不建议用isValidE…...
【大数据安全分析】大数据安全分析技术框架与关键技术
在数字化时代,网络安全面临着前所未有的挑战。传统的网络安全防护模式呈现出烟囱式的特点,各个安全防护措施和数据相互孤立,形成了防护孤岛和数据孤岛,难以有效应对日益复杂多变的安全威胁。而大数据分析技术的出现,为解决这些问题带来了新的曙光。 大数据分析在网络安全…...
PHP 中的除以零错误
除以零错误(Division by zero)是指数字除以零的情况, 这在数学上是未定义的。在 PHP 中,处理这种错误的方式取决于 PHP 版本: PHP 7: 使用 / 运算符会产生一个警告 (E_WARNING) 并返回 false。 使用 intd…...
【QT】控件 -- 多元素类 | 容器类 | 布局类
🔥 目录 一、多元素类1. List Widget -- 列表2. Table Widget -- 表格3. Tree Widget -- 树形 二、容器类1. Group Box -- 分组框2. Tab Widget -- 标签页 三、布局类1. 垂直布局【使用 QVBoxLayout 管理多个控件】【创建两个 QVBoxLayout】 2. 水平布局【使用 QHBo…...
数据结构——【二叉树模版】
#思路 1、二叉树不同于数的构建,在树节点类中,有数据,左子结点,右子节点三个属性,在树类的构造函数中,添加了变量maxNodes,用于后续列表索引的判断 2.GetTreeNode()函数是常用方法,…...
centos7 curl#6 - Could not resolve host mirrorlist.centos.org; 未知的错误 解决方案
问题描述 centos7系统安装完成后,yum安装软件时报错“curl#6 - “Could not resolve host: mirrorlist.centos.org; 未知的错误”” [root192 ~]# yum install vim -y 已加载插件:fastestmirror Determining fastest mirrors Could not retrieve mirro…...
