写点什么

TiDB 和 MySQL 的锁一些分析比对

  • 2022 年 7 月 11 日
  • 本文字数:2745 字

    阅读完需:约 9 分钟

原文来源:https://tidb.net/blog/1c1a2ab7


【是否原创】是


【首发渠道】TiDB 社区


【首发渠道链接】其他平台首发请附上对应链接


【正文】



图 1 锁分类图


一、悲观锁和乐观锁


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



悲观锁的详细介绍:



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 一致,即,可以多个事务加读锁,只能一个事务加写锁,兼容性表格如下所示:



图 2 读锁和写锁兼容表


其中 ok 表示可以兼容,即,可以一个事务对表格加读锁后,另一个事务继续加读锁,no 则表示部兼容


2.2 实验验证



图 3



图 4


读锁兼容性测试


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



图 5



图 6


写锁兼容性测试


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


三、表锁


TiDB 中的表锁默认是关闭的,show config where type = ‘tidb’ and name like ‘%enable-table-lock%’;



图 7


3.1 开启表锁


tiup cluster edit-config < 集群名字 >


在 tidb 中设置表锁为 true



图 8


tiup cluster reload < 集群名字 > -R tidb



图 9


3.2 表锁测试


TiDB 中设置表锁为 true 后,与 MySQL 有点不一样,MySQL 的根据有无命中索引,分别加行锁(命中索引)和表锁(未命中索引),TiDB 中不管有没有索引,均只锁定 update 的行


3.2.1 MySQL 表锁测试


person 表的主键和索引均是 ID 列



图 10



图 11



图 12


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


3.2.2 TiDB 表锁测试




图 13



图 14


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


3.2.3 手动对表加锁



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



图 16 TiDB 事务 2,加读锁后测试



图 17 TiDB 事务 1 手动对表加写锁



图 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 列做筛选条件



图 19 事务 1 中更新一条记录



图 20 事务 2 中更新数据


从图 20 中可以看出,图 19 事务 1 中更新的一行被锁住了,其余行都没有被锁住,可以照常更新。


4.1.2 TiDB 记录锁测试


TiDB 中的数据没有索引:




图 21 TiDB 事务 1 更新一行



图 22 TiDB 事务 2 更新数据


从图 22 中可以看出,TiDB 对事务 1 中的 1 行数据加了记录锁


记录锁相同和区别:


1、都会对一行数据加记录锁,


2、MySQL 加记录锁需要限制条件为索引列,TiDB 则不需要为索引列


4.2 间隙锁


间隙锁又称之为区间锁,每次锁定都是锁定一个区间,隶属行锁,MySQL 中照样需要限制条件为索引列


4.2.1 MySQL 间隙锁测试



图 23 事务 1 MySQL 间隙锁测试



图 24 事务 2 MySQL 间隙锁


从图 23 和图 24 中可以看出,MySQL 中间隙锁,是一个左开右闭的区间,并且对应区间内的范围都被锁住了,不可以执行插入操作。


4.2.2 TiDB 间隙锁测试



图 25 事务 1TiDB 间隙锁



图 26 事务 2TiDB 间隙锁


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


间隙锁相同和区别:


1、MySQL 中有间隙锁,并且是左开右闭区间


2、TiDB 中没有间隙锁


4.3 临键锁


临键锁即记录锁 + 间隙锁,mysql 的行锁默认就是使用的临键锁。


4.3.1 MySQL 临键锁测试



图 27 MySQL 事务 1 临键锁



图 28 MySQL 事务 2 临键锁


从图中测试可以看出,MySQL 中临键锁和间隙锁一样都是左开右闭的,并且当 id<8, 这个 8 不存在时,会自动向后锁住最近的 id=9。


4.3.2 TiDB 临键锁测试



图 29 TiDB 事务 1 临键锁测试



图 30 TiDB 事务 2 临键锁测试


从上面图中,可以发现,TiDB 并不会锁住区间,只会锁住限制条件区间中有的记录,命中的记录会被上锁,插入操作,可以正常进行。


临键锁相同和区别:


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


2、TiDB 中没有临键锁,只会锁住限制条件中的记录。


五、意向共享锁和意向排他锁


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


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


发布于: 刚刚阅读数: 2
用户头像

TiDB 社区官网:https://tidb.net/ 2021.12.15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
TiDB和MySQL的锁一些分析比对_实践案例_TiDB 社区干货传送门_InfoQ写作社区