MySQL事务隔离级别以及实现原理
一、事务完整性问题
脏读:可以读取其他事务未提交的数据,如果该事务回滚,则数据为错误数据。
不可重复读:A事务查看,B事务修改提交,A事务再次查看,数据不一样。
幻读:幻读与不可重复读相似,但不可重复读重点在于update和delete,幻读重点在于insert
t Session A Session B
|
| START TRANSACTION; START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| empty set
| INSERT INTO t_bitfly
| VALUES (1, 'a');
|
| SELECT * FROM t_bitfly;
| empty set
| COMMIT;
|
| SELECT * FROM t_bitfly;
| empty set
|
| INSERT INTO t_bitfly VALUES (1, 'a');
| ERROR 1062 (23000):
| Duplicate entry '1' for key 1
v (???刚刚明明告诉我没有这条记录的)
t Session A Session B
|
| START TRANSACTION; START TRANSACTION;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id | value |
| +------+-------+
| | 1 | a |
| +------+-------+
| INSERT INTO t_bitfly
| VALUES (2, 'b');
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id | value |
| +------+-------+
| | 1 | a |
| +------+-------+
| COMMIT;
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id | value |
| +------+-------+
| | 1 | a |
| +------+-------+
|
| UPDATE t_bitfly SET value='z';
| Rows matched: 2 Changed: 2 Warnings: 0
| (怎么多出来一行)
|
| SELECT * FROM t_bitfly;
| +------+-------+
| | id | value |
| +------+-------+
| | 1 | z |
| | 2 | z |
| +------+-------+
|
二、事务隔离级别
1. 读未提交(Read Uncommitted)
原理:任何操作都不加锁
2. 读提交(Read Commit)
原理:读操作不加锁,写操作加锁。读被加锁的数据时,读事务每次都读undo log中的最近版本,因此可能对同一数据读到不同的版本(不可重复读),但能保证每次都读到最新的数据。
3. 可重复读(Reapable Read)
原理:第一次读数据的时候就将数据加行锁(共享锁),使其他事务不能修改当前数据,即可实现可重复读。但是不能锁住insert进来的新的数据,当前事务读取或者修改的同时,另一个事务还是可以insert提交,造成幻读。
4. 串行化(Serializable)
原理:锁表,读锁和写锁阻塞。
三、InnoDB事务相关概念
● 当前读
读取记录的最新版本,读取时要保证其他事务不能不能修改该记录,通常对该记录加锁实现。
如:select ... lock in share mode; lock table table_name read; -- 共享锁(并发时可以继续加锁)
select ... for update; insert .....; update ...; delete ...; -- 排他锁(并发时只有一个事务持有锁)
● 快照读
非阻塞读,如非串行隔离级别的select(串行隔离级别下select退化为当前读)。该设计可以实现读-写不冲突,也减少了行锁使用,降低了开销。它的实现基于多版本并发控制,即MVCC。
● redo log
MySQL在开启事务时,会将执行的SQL保存到指定的log文件,即redo log。当MySQL执行recovery时执行redo log里的SQL操作即可。redo log不会被立即写入磁盘,会先写入redo buffer;当客户端执行commit时,redo buffer的内容会视情况存入磁盘。
● undo log
与redo log相反,undo log是为了回滚事务而写的日志,具体内容就是copy事务开始前的数据(行)到undo buffer。
undo log分为两种:
insert undo log:执行insert新记录时产生,只在回滚是用到,提交事务后可以立即丢弃;
update undo log:执行update/delete时产生,不仅在回滚时用到,在快照读时也需要,所以不能随意丢弃。只有在快照读或事物回滚不涉及该日志时,才会被purge线程统一清除。它对MVCC有着实质性的帮助。
与redo buffer一样,undo buffer也是环形缓冲,当缓冲满的时候buffer内容会被刷新到磁盘。
与redo log不同的是,undo log没有独立的磁盘文件,所有的undo log均被存在主ibd数据文件中(表空间)。
四、MVCC
MVCC,Mult-Version-Concurreny-Control,多版本并发控制,是数据库控制并发访问的一种手段,在mysql,oracle,PostgreSQL中都有应用。
通常只有在读提交和可重复读的隔离级别才会应用该模式。
在MySql中是在InnoDB的引擎级别实现的。
1. MVCC的作用:
- 不加锁的情况下处理读写冲突(读的时候不阻塞写,写的时候不阻塞读),提高访问性能,减少开销。
- 解决脏读、幻读、不可重复读等问题,但不能解决更新丢失问题(并发写)。
2. MVCC的实现:三个隐式字段+版本链(undo log)+一致性视图(Read View)
(1)Innodb隐式字段
- DB_TRX_ID:6byte,存储修改了此数据行的事务id,当事务对数据做了修改操作(insert/update/delete)后,才会为其分配唯一的DB_TRX_ID。DB_TRX_ID是自增的。
- DB_ROLL_POINTER:7byte,回滚指针,用于配合undo long,指向上一个版本(存储于rollback segment)。
- DB_ROW_ID:6byte,当表没有主键,并且没有不允许为null的唯一索引时,InnoDB会以DB_ROW_ID创建聚簇索引。
purge线程:
InnoDB的版本记录还有个隐式标志位字段(deleted_bit),用来标记记录是否被删除。为了实现MVCC机制,update/delete都不会直接删除老的版本,而且设置一下老版本的deleted_bit。
为了节省磁盘空间,InnoDB有专门的purge线程来清理deleted_bit = true的版本记录。
又为了不影响MVCC的正常工作,purge线程也维护了一个自己的Read View(这个Read View相当于系统中最老活跃事务的Read View)。如果一版本记录deleted_flag = true,并且BD_TRX_ID相对于purge线程的Read View可见,那么这条记录一定是可以被安全清除的。
(2)版本链
版本链是一种链表,由数据行的修改记录构成,由数据行的聚簇索引包含的两个隐藏字段(DB_TRX_ID, DB_ROLL_POINTER)连接。
select * from t_user;
name | age | DB_ROW_ID | DB_TRX_ID | DB_ROLL_POINTER |
a | 1 | 1 | null | null |
update t_user set name = 'b';
第一步:开启事务1,对记录加排它锁;
第二步:拷贝记录到undo log,作为一个旧版本;
第三步:修改行数据name 'a' ->'b'; 修改隐式字段事务id为当前事务1的id;回滚指针指向undo log的版本记录;
第四步:提交事务,释放锁。
update t_user set age = 2 ;
第一步:开启事务2,对记录加排它锁;
第二步:拷贝记录到undo log,发现该记录已经有undo log了,DB_TRX_ID=1的undo log就成了版本链表的表头;
第三步:修改行数据age 1 ->2; 修改隐式字段事务id为当前事务2的id;回滚指针指向事务1创建的的版本记录;
第三步:提交事务,释放锁。
可以看出,版本链是由不同事务修改同一记录而产生的undo log链表,链首是最新的版本,链尾是最老版本。
上面讲purge线程的时候提到过,版本记录不被用到时会被purge线程清除,事务1提交后DB_TRX_ID=1的线程可能已经被清除了,所以链表也不一定能够形成。
(3)一致性视图(Read View)
当某行数据存在版本链时去读取它,应该读取哪个版本呢?
开启事务后,执行快照读的那一刻,会生成当前数据库系统的一个快照(RC和RR的生成时机不一样,RC下每次select都会生成,RR只在第一次select生成,这是两种隔离级别的主要区别),记录并维护此时活跃的所有的事务id(DB_TRX_ID),这个快照就是Read View。
一致性视图主要用于版本可见性判断。
InnoDB会比较当前事务的DB_TRX_ID与Read View里维护的DB_TRX_ID。
trx_ids: 生成Read View时,当前活跃的事务id列表;
min_trx_id: trx_ids的最小值;
max_trx_id: trx_ids的最大值+1;
creator_trx_id: 生成该事务的事务id(单开启事务是没有事务id的,默认为0,creator_trx_id为0)。
版本链中的某个版本是否可以被当前事务可见,根据如下情况判断:
- 当trx_id = creator_trx_id时,当前事务可以看到自己修改的数据,可见;
- 当trx_id < min_trx_id时,生成此数据(版本链)的事务已经提交了,可见;
- 当trx_id > max_trx_id时,表明生成此数据的事务是在生成此Read View后才开启的,不可见;
- 当min_trx_id < trx_id < max_trx_id时,
- trx_id在trx_ids里面,说明生成当前Read View时,活跃事务还未提交,不可见;
- trx_id不在trx_ids里面,说明事务在生产当前Read Veiw时已经提交了,可见。
不可见时,就要顺着版本链找下一个版本。
MySQL事务隔离级别以及实现原理相关推荐
- mysql事务隔离级别及实现原理
mysql事务 Markdown编辑器用的不顺手,自己选的,跪着也要用完. 事务通俗的来讲就是SQL要么全部执行成功,要么全部执行失败回滚到执行前的状态.不存在部分执行成功,部分执行失败 ...
- MySQL事务隔离级别和实现原理
经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢?本文就帮大家梳理一下. MySQL 事务 本文所说的 MySQL 事务都是指在 I ...
- 一文讲清楚MySQL事务隔离级别和实现原理,后台开发人员必备知识
经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗,事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢?本文就帮大家梳理一下. MySQL 事务 本文所说的 MySQL 事务都是指在 I ...
- mysql事务隔离级别之锁实现原理,脏读、不可重复读、幻读出现原因及解决方案
mysql事务隔离级别原理 观看了很多网上的博客,挺令人伤心,很难找到想要的答案... 一:所需知识 1,mysql中的锁 1.1,读锁(共享锁) 规则:若事务1对数据对象A加上读锁,则事务1只能读A ...
- mysql 事务隔离级别实现原理_MySQL事务隔离级别和实现原理 - 米扑博客
开发中经常提到数据库的事务,那你知道数据库还有事务隔离的说法吗, 事务隔离还有隔离级别,那什么是事务隔离,隔离级别又是什么呢? MySQL 事务 本文所说的 MySQL 事务都是指在 InnoDB 引 ...
- 5、MySQL事务隔离级别详解
事务的隔离性就是指当多个事务同时运行时,各事务之间相互隔离,不可互相干扰.如果事务没有隔离性,就容易出现脏读.不可重复读和幻读等情况. 为了保证并发时操作数据的正确性,数据库都会有事务隔离级别的概念. ...
- Mysql事务隔离级别及MVCC(多版本并发控制)
一.MySQL事务隔离级别 先注明一点:以下讨论都是在多事务并发的情境下讨论的 事务的特性(InnoDB引擎才有事务): ACID 原子性:一个事务不可再分割,要么都执行要么都不执行 一致性:一个事务 ...
- mysql 事务 隔离级别_MySQL的四种事务隔离级别
https://www.cnblogs.com/huanongying/p/7021555.html 本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB 一.事务的 ...
- mysql事务隔离级别 花_mysql事务隔离级别
很多PHP开发者在面试的时候遇到这个问题都会卡壳.这是因为理解得不够透彻,今天让我带领大家梳理一下mysql事务隔离级别 数据库有四种隔离级别,分别是Read uncommitted,Read com ...
最新文章
- 深度有趣 | 06 变分自编码器
- 共享资源的保护:锁机制
- 三、MySql查询语句执行的特征
- XCTF-高手进阶区:Web_php_include
- 求字典key的和python_python怎么将字典key相同的value值, 合并
- Xcode 静态库调试策略
- 03-14 设备交互 API
- 【汇编语言与计算机系统结构笔记20】补充内容:可定制处理器指令集
- matlab2c使用c++实现matlab函数系列教程-perms函数
- 软件测试综合笔试题目及参考答案
- Koa2 之文件上传下载
- abaqus Isight学习
- 怎么把短视频做成表情包?短视频制作gif只需三步
- 3小时快学期权(第二版)读书笔记(上)
- 【考研英语】词汇积累(详细全面,2023最新版)
- 心情手札——光头日记
- Part 1 ——ActiveMQ 概述
- Ubuntu20.04LTS 安装QQ 微信 钉钉 最简单,最好用的方式!
- 大华 / 海康威视(HIKVISION) 网络视像头的连接及使用
- Windows系统提示“telnet不是内部或外部命令,也不是可运行的程序或批处理文件”怎么办