0
2
2
0
专栏/.../

TiDB和MySQL的锁一些分析比对

 变又未变  发表于  2021-11-19

【是否原创】是
【首发渠道】TiDB 社区
【首发渠道链接】其他平台首发请附上对应链接
【正文】

image


图1 锁分类图

一、悲观锁和乐观锁
TiDB一开始是乐观锁,但自TiDB3.0版本开始,支持悲观事务,并且在3.0.8版本开始默认使用悲观事务,支持悲观锁,查看事务:show variables like ‘%tidb_txn_mode%’;
image
悲观锁的详细介绍:

TiDB 悲观锁实现原理 原理解读

在上一篇《白话悲观锁》中我们介绍了什么是悲观锁,悲观锁的使用场景,以及与 MySQL 的区别和联系。本文我们将深入底层,从开发者的角度,分享悲观锁的实现细节,希望能够让大家在熟悉悲观锁的同时,具备参与到相关优化中来的能力。 此外,TiDB 先有乐观锁后有悲观锁,两者共享了不少逻辑,本文将重点关注悲观锁独有的实现细节,与乐观锁相关的更多逻辑部分大家可以在《乐观事务》查阅。 鸟瞰悲观锁 TiDB …


TiDB 4.0 新特性前瞻:白话“悲观锁” 原理解读

作者:Shirly 如果说在 TiDB 3.0 中,悲观锁是 “千呼万唤始出来,犹抱琵琶半遮面”。那么在 TiDB 4.0 中,悲观锁在经历了市场与时光的考验后,无论是性能还是稳定性都能够 “轻拢慢撚抹复挑,初为《霓裳》后《六幺》”,欢迎大家尝鲜与反馈。本文将从使用者的角度,介绍悲观锁的使用与注意事项,主要分为以下几方面: 白话悲观锁 TiDB 悲观锁的使用和常见现象 TiDB 悲观锁与…

二、共享锁和排他锁
2.1 基本介绍
共享锁(Share Lock),又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。
排他锁(eXclusive Lock),又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。
这里的特性与MySQL一致,即,可以多个事务加读锁,只能一个事务加写锁,兼容性表格如下所示:

image


图2 读锁和写锁兼容表
其中ok表示可以兼容,即,可以一个事务对表格加读锁后,另一个事务继续加读锁,no则表示部兼容
2.2 实验验证
image
图3

image


图4
读锁兼容性测试
上面一幅图3是事务1,下面一幅图4是事务2,从上面的实验可以看出,加读锁后,可以继续加读锁,读锁相互兼容,读锁和写锁不兼容。
image
图5

image


图6
写锁兼容性测试
上图5是事务1,下图6是事务2,从上面实验可以看出,先加写锁后,后续不可以再添加读锁和写锁了。

三、表锁
TiDB中的表锁默认是关闭的,show config where type = ‘tidb’ and name like ‘%enable-table-lock%’;
image
图7
3.1 开启表锁
tiup cluster edit-config <集群名字>
在tidb中设置表锁为true
image
图8
tiup cluster reload <集群名字> -R tidb
image
图9
3.2 表锁测试
TiDB中设置表锁为true后,与MySQL有点不一样,MySQL的根据有无命中索引,分别加行锁(命中索引)和表锁(未命中索引),TiDB中不管有没有索引,均只锁定update的行
3.2.1 MySQL表锁测试
person表的主键和索引均是ID列

image


图10
image
图11
image
图12
从图11和图12对比可以看出,MySQL中当未命中索引时,会使用表锁,锁住整个表
3.2.2 TiDB表锁测试
image

image


图13

image


图14
从图13和图14可以看出,TiDB并没有自动加表锁,事务2可以对其他行照常更新,MySQL则会加表锁。

3.2.3 手动对表加锁
image
图15 TiDB事务1手动对表加读锁

image


图16 TiDB事务2,加读锁后测试
image
图17 TiDB事务1手动对表加写锁

image


图18 TiDB事务2手动加写锁后测试
从图15,16,17,18中,可以看出,在事务1中,手动对TiDB的表格加锁后,也是会锁住整张表,此时在其他事务中,不可以对该表增,删、改操作

TiDB与MySQL的表锁的区别:
1、MySQL表锁由update语句未使用索引,自动添加,TiDB默认表锁是关闭的,需要手动开启,并且手动添加;
2、MySQL执行更新操作时,由于未命中索引,会主动对整张表加表锁,TiDB则是只会对那一行数据加行锁,
我理解这么做的原因是:TiDB是分布式数据库,一个大表的数据分布在多个节点的tikv实例是,如果要对整张表加锁,这样对CPU、IO的资源都是一种损耗,同时这样加表锁,也不利于并发,是这样嘛,或者还有什么其他原因?

四、行锁
4.1 记录锁
记录锁是在行锁之上引申的锁,记录锁锁的是表中的某一条记录,MySQL中记录锁的出现条件必须是精准命中索引并且索引是唯一索引,如主键id,TiDB好像不需要索引
4.1.1MySQL记录锁测试
使用主键ID列做筛选条件
image
图19 事务1中更新一条记录
image
图20 事务2中更新数据
从图20中可以看出,图19事务1中更新的一行被锁住了,其余行都没有被锁住,可以照常更新。
4.1.2 TiDB记录锁测试
TiDB中的数据没有索引:
image
image
图21 TiDB事务1更新一行
image
图22 TiDB事务2更新数据
从图22中可以看出,TiDB对事务1中的1行数据加了记录锁

记录锁相同和区别:
1、都会对一行数据加记录锁,
2、MySQL加记录锁需要限制条件为索引列,TiDB则不需要为索引列

4.2 间隙锁
间隙锁又称之为区间锁,每次锁定都是锁定一个区间,隶属行锁,MySQL中照样需要限制条件为索引列
4.2.1 MySQL间隙锁测试
image
图23 事务1 MySQL间隙锁测试
image
图24 事务2 MySQL间隙锁
从图23和图24中可以看出,MySQL中间隙锁,是一个左开右闭的区间,并且对应区间内的范围都被锁住了,不可以执行插入操作。
4.2.2 TiDB间隙锁测试

image


图25 事务1TiDB间隙锁

image


图26 事务2TiDB间隙锁
从图25和26可以看出,TiDB中没有间隙锁

间隙锁相同和区别:
1、MySQL中有间隙锁,并且是左开右闭区间
2、TiDB中没有间隙锁

4.3 临键锁
临键锁即记录锁+间隙锁,mysql的行锁默认就是使用的临键锁。
4.3.1 MySQL临键锁测试
image
图27 MySQL事务1临键锁
image
图28 MySQL事务2临键锁
从图中测试可以看出,MySQL中临键锁和间隙锁一样都是左开右闭的,并且当id<8,这个8不存在时,会自动向后锁住最近的id=9。
4.3.2 TiDB临键锁测试
image
图29 TiDB事务1临键锁测试
image
图30 TiDB事务2临键锁测试
从上面图中,可以发现,TiDB并不会锁住区间,只会锁住限制条件区间中有的记录,命中的记录会被上锁,插入操作,可以正常进行。

临键锁相同和区别:
1、MySQL临键锁会锁住限制条件中的区间和记录,并且和间隙锁一样都是左开右闭的,并且当id<8,这个8不存在时,会自动向后锁住最近的id=9。
2、TiDB中没有临键锁,只会锁住限制条件中的记录。

五、意向共享锁和意向排他锁
意向锁是表级锁,可以分为意向共享锁和意向排他锁。当事务要在记录上加上读锁或写锁时,要首先在表上加上意向锁。通过看表上是否有意向锁,判断表中是否有记录加锁。意向锁是数据库自动完成的,即事务1加锁时,数据库会自动先开始申请表的意向锁,事务2就可以检测这个意向锁,判断对应的记录有没有锁,从而不需要遍历整个表,提高效率。

注:整理了这些,欢迎大家看后提供意见,交流,谢谢!

0
2
2
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论