MySQL数据库Innodb 引擎实现mvcc锁


Posted in MySQL onMay 06, 2022

前言:

大家都知道在java 开发过程中,会经常用到锁,在java 代码中,我们都知道锁是加在对象头上的,在java对象布局中有锁的标志位。程序通过判断锁的标志位来获取加锁的情况。但是在mysql 中,锁的实现原理是什么呢。可能大家都听过 mvcc,但是mvcc 的实现原理是什么呢,可能就说不太清楚了,本文就以实例说明来mvcc 的实现原理。

1 数据库设置隔离级别

我们都知道数据库的隔离级别可以分为以下:

  • 读未提交 RU : read uncommitted  
  • 读提交   RC : read committed 
  • 可重复读 RR : repeatable read 默认隔离级别
  • 序列化   SE : serializable 序列化

我们使用select @@transaction_isolation;来查看数据库的隔离级别,可能有读者会有疑问了,不是应该是select @@tx_isolation;吗, 因为我的电脑上装的是 mysql 8.0, 之前的 tx 也是 transaction的简写,高版本的mysql 已经使用 transaction 了。

# 查询当前会话隔离级别
select @@transaction_isolation;
# 查看当前系统的隔离级别
select @@global.transaction_isolation;
# 命令行开启事务,区别在于前者是第一条语句的执行时间点为事务开始的时间点,建立一致性读,后者是立即建立一致性读,开始执行事务
start transaction 或者 start transaction with consistent snapshot
# 设置数据库隔离级别,如若设置会话级别,则修改 global 为session 即可
set global transaction isolation level REPEATABLE READ;
set global transaction isolation level READ COMMITTED;
set global transaction isolation level READ UNCOMMITTED;
set global transaction isolation level SERIALIZABLE;

2 数据库表以及案例操作

操作的数据库表为:

CREATE TABLE `t_user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `age` int DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
# 初始化语句
INSERT INTO `t_user`(`id`, `age`) VALUES (1, 3);
# 使用的操作语句
select * from t_user where id = 1;
update t_user set age = age + 1  where id = 1;

案例如图所示:

MySQL数据库Innodb 引擎实现mvcc锁

 sessionA,sessionB,sessionC 是连接数据库的3个会话窗口,mysql 数据库的默认隔离级别为RR,为了达到效果我们把当前的数据库隔离级别改为RC,语句如下:

set session transaction isolation level READ COMMITTED;

setp1 准备工作,设置当前会话事务隔离级别,查看数据库表中的数据。窗口从左往右依次是sessionA、sessinB和sessionC。 

MySQL数据库Innodb 引擎实现mvcc锁

setp2 t1 时刻,sessionA 和 sessionB 开启事务。sessionA t2 时刻执行查询语句,sessionC 执行更新操作,可以看到此时 sessionC 立马执行成功。 

MySQL数据库Innodb 引擎实现mvcc锁

step3 t3 时刻,sessionB 查询最新的数据,并执行更新操作 

MySQL数据库Innodb 引擎实现mvcc锁

step4 t4 时刻,sessionA 查询最新数据,并在t5 时刻更新数据,这里因为sessionB 的事务还未结束,因此执行的操作会阻塞到超时(这里刻意等待到超时),t6 时刻sessionB 查询数据,并提交事务。 

MySQL数据库Innodb 引擎实现mvcc锁

step5 sesionB 提交事务后,sessionA 重新执行语句,可以看到执行后的结果,然后提交事务。 

MySQL数据库Innodb 引擎实现mvcc锁

通过上述的操作案例,我们可以观察到:

  • 在一个事务中的数据更改对本事务是可见的,此外的事务是否可见取决于其隔离级别。
  • 两个事务操作同一条数据,会造成等待。innodb 引擎默认开启死锁检测,并会设置锁的超时时间。
# 设置超时时间默认是50s
innodb_lock_wait_timeout 
# 开启死锁检测,默认是开启死锁检测,默认值为 on,开启死锁检测
innodb_deadlock_detect
# 查看更多innodb 引擎的配置
show variables like '%innodb%'
  • 在会话中进行数据修改,默认事务是自动提交的。

3 mvcc 实现原理

mvcc,Multi-Version Concurrency Control,即版本并发访问控制,是 mysql innodb 引擎实现的一种并发访问控制方法,用于其事务的实现。其主要作用是为了提高数据库的并发性能,更好地处理读写冲突问题,在遇到冲突的境况也能够做到不加锁,非阻塞并发读取数据。 在解释实现原理前,先了解一下当前读和快照读。

  • 当前读:像更改数据的操作(update/delete/insert)操作还有共享锁和排他锁(lock in share mode和for update)这操作都需要读取当前最新版本的数据,否则就会有更新丢失的情况。数据库的修改操作也是将数据所在的数据页从磁盘加载到内存,然后进行修改,最后写回到磁盘中。
  • 快照读:不加锁的select获取数据就是读快照,不会产生阻塞。在串行化的数据库隔离级别下,快照读会退化成当前度。每行数据都有多个版本,当前读就是获取最新的已经提交过得版本数据。

接下来讲述的是非常重要的部分:

  • 已经提交的事务
  • 未被提交的事务
  • 未开始的事务

在可重复读的隔离级别下,事务启动需要对整个库做备份,这显然是不可能的,实际上mvcc也没有这样做,而是利用版本号来控制,也就是事务开始时向 innodb 事务系统申请一个 transaction id,这个id申请顺序是严格递增的。每行数据的版本号 row trx_id = transaction id , 也就可以保证其版本的唯一性。可以保证事务启动时,会获取当前所有活跃事务id的数组,可以保证其唯一性。事务id数组中的最小的id记为低水位,数组中的最大id+1记为高水位。低水位和高水位便是已经提交的事务-未提交的数据、未提交的事务-未开始的事务的分界标志位,以上就组成了当前事务的一致性视图(read-view)。

前面已经提到了,所有的数据都是有版本的,这个版本即row trx_id。当需要读快照时,就需要读取trx_id小于低水位且最大的trx_id版本号的数据。读当前就是读取当前最新版本的数据,如果数据正在事务的处理中,那么久需要等待,这也是为什么会出现锁等待超时的情况。

当在RC的数据库隔离级别下,每次的操作都会重新获取当前活跃的trx_id数组,形成新的一致性视图,这就是sessionB 在t3 时刻读取到了sessionC 在t2时刻提交的数据,因为在新的一致性视图中,sessionC 的trx_id 已经已经提交的事务了,所以就可以读取到。在sessionA 的t5 时刻,拿到的一致性视图中活跃的trx_id 数组中包含 sessionB 的活跃id,因为在更新数据时,需要当前读,而数据已经被锁住,所以出现了锁超时的情况。

而在RR的数据库隔离级别下,在事务开始时生成一个一致性视图,此后在事务提交之前,其 trx_id 数组不会发生变化,这样才能保证其可重复读的特性。RR相对于RC实现简单,区别在于是否在执行语句前更新一致性视图,活跃事务id的数组是否更新。

综上,我们就知道了mvcc 是如何实现可重复读和读提交的隔离级别了。

4 ACID 的实现

  • 事务的原子性 A 是通过 undolog 回滚日志来实现。
  • 事务的持久性 C 性是通过 redolog 重做日志来实现的。
  • 事务的隔离性 I 是通过 MVCC 来实现的。
  • 原子性,持久性,隔离性都实现了,那么一致性 D 也就实现了。

redo log 是mysql innodb 引擎产生的物理日志,其大小有一定的限制,采用循环写入的方式,写满之后进行刷盘。主要用于宕机后的数据恢复。redo log是一个循环写入的日志,可以理解为一个环,有 checkpoint 和 write pos 两个标志点,checkpoint之前的空间是清除后的可写空间,清除之前会更新到磁盘中,write pos是数据写入的位置,当两个标志点相遇表明redo log已经满了,这时数据库停止进行数据库更新语句的执行,转而进行redo log日志同步到磁盘中。

binlog 是mysql server 层记录逻辑的日志,可以一致追加写入,主要用于主从数据同步。

到此这篇关于MYSQL数据库Innodb 引擎mvcc锁实现原理的文章就介绍到这了!


Tags in this post...

MySQL 相关文章推荐
MySQL基础(二)
Apr 05 MySQL
MySQL系列之十二 备份与恢复
Jul 02 MySQL
MySQL数据库必备之条件查询语句
Oct 15 MySQL
MySQL利用UNION连接2个查询排序失效详解
Nov 20 MySQL
彻底解决MySQL使用中文乱码的方法
Jan 22 MySQL
利用JuiceFS使MySQL 备份验证性能提升 10 倍
Mar 17 MySQL
MySQL Server 层四个日志
Mar 31 MySQL
MySQL创建管理HASH分区
Apr 13 MySQL
MySql数据库 查询时间序列间隔
May 11 MySQL
mysql数据库实现设置字段长度
Jun 10 MySQL
MySQL主从切换的超详细步骤
Jun 28 MySQL
MySQL索引失效场景及解决方案
Jul 23 MySQL
讲解MySQL增删改操作
May 06 #MySQL
解决Mysql报错 Table 'mysql.user' doesn't exist
MYSQL常用函数介绍
May 05 #MySQL
MySQL 数据 data 基本操作
May 04 #MySQL
MySQL 字符集 character
May 04 #MySQL
MySQL 数据表操作
May 04 #MySQL
MySQL 执行数据库更新update操作的时候数据库卡死了
May 02 #MySQL
You might like
ajax+php打造进度条 readyState各状态
2010/03/20 PHP
php适配器模式介绍
2012/08/14 PHP
采用header定义为文件然后readfile下载(隐藏下载地址)
2014/01/31 PHP
迁移PHP版本到PHP7
2015/02/06 PHP
Javascript笔记一 js以及json基础使用说明
2010/05/22 Javascript
js面向对象 多种创建对象方法小结
2012/05/21 Javascript
js判断屏幕分辨率的代码
2013/07/16 Javascript
代码触发js事件(click、change)示例应用
2013/12/13 Javascript
js实现动态改变字体大小代码
2014/01/02 Javascript
javascript实现仿腾讯游戏选择
2015/05/14 Javascript
js实现带圆角的两级导航菜单效果代码
2015/08/24 Javascript
JavaScript 数组some()和filter()的用法及区别
2016/05/20 Javascript
jquery 删除节点 添加节点 找兄弟节点的简单实现
2016/12/07 Javascript
基于JavaScript实现前端数据多条件筛选功能
2020/08/19 Javascript
vue中使用ueditor富文本编辑器
2018/02/08 Javascript
轻松搞定jQuery+JSONP跨域请求的解决方案
2018/03/06 jQuery
详解从NodeJS搭建中间层再谈前后端分离
2018/11/13 NodeJs
JavaScript中构造函数与原型链之间的关系详解
2019/02/25 Javascript
layui监听工具栏的实例(操作列表按钮)
2019/09/10 Javascript
详解js创建对象的几种方式和对象方法
2021/03/01 Javascript
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
Python中itertools模块用法详解
2014/09/25 Python
python list是否包含另一个list所有元素的实例
2018/05/04 Python
根据DataFrame某一列的值来选择具体的某一行方法
2018/07/03 Python
图文详解Django使用Pycharm连接MySQL数据库
2019/08/09 Python
Windows10下 python3.7 安装 facenet的教程
2019/09/10 Python
制作部班长职位说明书
2014/02/26 职场文书
保卫科工作岗位职责
2014/03/01 职场文书
元旦促销方案
2014/03/15 职场文书
毕业自我鉴定总结
2014/03/24 职场文书
信仰心得体会
2014/09/05 职场文书
小学生2014国庆节演讲稿:祖国在我心中
2014/09/21 职场文书
项目合作协议书
2014/09/23 职场文书
2014乡镇班子个人对照检查材料思想汇报
2014/09/26 职场文书
考试没考好检讨书
2015/05/06 职场文书
详解mysql三值逻辑与NULL
2021/05/19 MySQL