IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> mysql中锁的理解与LBCC详解 -> 正文阅读

[大数据]mysql中锁的理解与LBCC详解

一.mysql中锁的介绍

本文默认是基于mysql的innoDB存储引擎描述,并且版本是mysql5.7 不同的版本可能存在一些差异

1. 按照模式划分

共享锁(S Lock):可以分为共享锁和意向共享锁(IS)

排它锁(X Lock):分为排它锁和意向排它锁(IX)

共享锁和排他锁与我们平时所了解读写锁是非常类似的

锁的兼容性如下表:

ISIXSX
IS兼容兼容兼容不兼容
IX兼容兼容不兼容不兼容
S兼容不兼容兼容不兼容
X不兼容不兼容不兼容不兼容

2. 验证及使用

我们来验证上述的表格的内容

CREATE TABLE `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `number` INT(11) NOT NULL,
  `name` VARCHAR(255) COLLATE utf8_bin NOT NULL,
  `age` INT(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_number` (`number`) USING BTREE,
  KEY `idx_name` (`name`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

(1) 共享锁与共享锁兼容

事务1事务2
begin;
begin;
select * from user where id=1 lock in share mode;
select * from user where id=1 lock in share mode;

执行结果:

在这里插入图片描述

(2)共享锁与独占锁不兼容

事务1事务2
begin;
begin;
select * from user where id=1 lock in share mode;
select * from user where id=1 lock in share mode;

执行结果:

在这里插入图片描述

其他的就不做验证了,因为这些都不是本文的重点内容

3. 意向锁的意义

mysql既然已经分为了共享锁和排他锁,为什么还要加入意向锁呢?

我们知道mysql即存在航锁,也存在表锁,那么假设存在如下情况

当mysql一个事务已经为一条记录加了行锁,现在又一个事务需要加表锁,显然第二次加表锁需要阻塞的。不然第二个事务和第一个事务都能够操作数据了。

那么mysql在增加表锁的时候,需要每一行记录都去判断有没有加行锁吗?这样效率太低了,msql可不会这么干的,所以就引入了意向锁。

那么mysql如何使用意向锁呢?

比如上面的实例,mysql在给一行记录添加行排它锁时,首先给这个表增加一个表排它意向锁,添加成功后才能添加行锁

然后第二个事务想添加表排它锁时首先只需要判断有没有意向锁,如果有就阻塞,这样只需要判断一次即可,大大提升性能

意向锁就不重点介绍了,也不是本文的重点。

二. LBCC

LBCC(Lock-Base Concurrency Control)基于锁的并发控制,这是本文的重点

在前面的文章中我们学习过MVCC,我们知道MVCC基于多版本控制可以提升mysql的并发读写能力,但是不能完全解决幻读,以及并发写的问题(出现更新丢失);那么今天我们来看看LBCC是如何处理并发写,以及处理幻读。

1. 锁定读与快照读

锁定读:貌似又有人称呼它为当前读

select * from user for update;#排它锁

select * from user lock for share lock;#共享锁

快照读:貌似又有人称呼它为一致性读

select *from user;

2. 锁的范围

表锁:锁住整张表

行锁:record lock,只锁住一行记录

间隙锁:锁定一个范围,但是不包括记录本省

Next-Key Lock:行锁 + 间隙锁 左开右闭

Previous-Key Lock:行锁 + 间隙锁 左闭又开

mysql在REPEATABLE READ隔离级别下默认是使用Next-Key Lock,但是会存在锁升级或者降级的情况

(1)如果没有索引,或者索引失效,则升级为表锁

(2)主键索引和唯一索引直接降级成行锁

3. 验证

下面我们来做实验验证一下,上述的结论

建表语句如下:

CREATE TABLE `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `number` INT(11) NOT NULL,
  `name` VARCHAR(255) COLLATE utf8_bin NOT NULL,
  `age` INT(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_number` (`number`) USING BTREE,
  KEY `idx_name` (`name`) USING BTREE
) ENGINE=INNODB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

#向表中插入如下记录
INSERT INTO USER(id,number,`name`,age) VALUES (1,1,'1',1);

INSERT INTO USER(id,number,`name`,age) VALUES (11,11,'11',11);

INSERT INTO USER(id,number,`name`,age) VALUES (21,21,'21',21);

INSERT INTO USER(id,number,`name`,age) VALUES (31,31,'31',31);

INSERT INTO USER(id,number,`name`,age) VALUES (41,41,'41',41);


其中id是主键,number是唯一索引,name是普通索引,age没有索引

(1)锁定主键记录

操作步骤

事务1事务2
begin;
begin;
select * from user where id=11 for update;
update user set name=‘111’ where id=11;#(1)
insert into user (id,number,name,age) values(5,5,“5”,5);#(2)
commit;
select * from user;
commit;

执行结果

在这里插入图片描述

解析:

1.#(1)不能够更新id=11的数据,因为被加了行锁

2.#(2)可以插入,说明没有gap锁,下面解析gap范围

按照主键记录形成的区间如下:

(-∞,1] (1,11] (11,21] (21,31] (31,41] (41,+∞]

如果是使用的间隙锁,那么当我锁定主键11时,应该锁定的区间(1,11] (11,21],如果是这样,那么我们是不能够插入id=5的数据的,但是事实上是插入成功的,所以证明此时不是使用的Next-Key Lock而是使用的行锁

(2)锁定唯一索引

锁定唯一索引我已经测试过了和上述的结果一样,大家可以自行测试

(3)表锁

上面的表中age是没有索引的,那么此时应该锁定一条记录时,会锁住整个表

操作步骤

事务1事务2
begin;
begin;
select * from user where age =11 for update;
update user set name = “411” where id= 41;#(1)
update user set name = “311” where id= 31;#(2)
update user set name = “211” where id= 21;#(3)
insert into user(id,number,name,age)values(51,51,‘51’,51);#(4)
commit;
commit;

执行结果:

在这里插入图片描述

解析:

我们从上面的图上可以看出,当我们锁定了age=11的记录时,此时右边的部分多个范围都不能更新,也不能插入,说明发生了表锁,为什么会发生表锁呢?

我是这么理解的:因为age上面没有索引约束,那么其实任何一条记录,都可能修改成age=11,所以mysql想用行锁或者想用gap锁,根本就锁不了。假如其他的行能够修改(或者新增)成age=11,那么与左边第一次查询的结果就有冲突了(左边查询的是一条,如果其他行也修改成age=11或者新增一条age=11的记录),这就有问题了,所以mysql为了保证不出现这样的问题,就锁住整个表了。

(4)普通索引

普通索引就会使用Next-Key Lock,我们来测试一下,上面的表中name是普通索引

操作步骤

事务1事务2
begin;
begin;
select * from user where age =21 for update;
update user set name = “211” where id= 21;#(1)
insert into user(id,number,name,age)values(15,15,‘15’,15);#(2)
insert into user(id,number,name,age)values(25,25,‘25’,25);#(3)
commit;
commit;

执行结果:

在这里插入图片描述

解析:

上面的执行结果图上很明显的显示当锁住name='21’时,是无法更新name="21"这条记录,同时也不能插入name='15’和name='25’的记录,这就说明了此时使用了是 行锁 + Gap锁(间隙锁),其实此处不仅仅不能插入name为11-31之间的数据,同时name='155’和’255’也不能插入,这是因为name是varchar类型的,‘155’和’255’也在’11’he '31’这个范围。验证图如下:

在这里插入图片描述

本文就先到这里了,其实还有一些内容没有写完,就是区分Previous-Key Lock和Next-Key Lock.,这个表设计的不太方便测试这个,下次有时间再测试吧,大家也可以自行测试。先睡觉了熬夜干文章太累了。

最后再补充一个技巧吧,因为我在测试的时候,secureCrt断开与服务器链接,导致我的会话事务没有关闭,所以锁没有释放,可以通过下面的语句查询thread_id然后kill thread_id即可

select t.trx_mysql_thread_id from information_schema.innodb_trx t;
kill xxx;
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-09-06 11:13:37  更:2021-09-06 11:14:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:29:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码