暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

MySQL锁分类和行锁实现方式

原创 凡尘dba 2023-03-31
414
为了保证数据并发访问的原子性、完整性、一致性,数据库引入了锁的概念,只要对数据加锁,数据就无法改变,只有加锁者释放了锁,别人才能改变数据。
但与此同时,加锁也增加了系统开销,有可能产生锁等待,造成数据库运行异常。
所以,锁冲突就成为了影响数据库并发访问性能的一个重要因素。


锁的分类

根据加锁的范围,MySQL 里面的锁大致可以分成行级锁、表级锁和全局锁三类。


行级锁

1、根据兼容性分类

根据锁的兼容性,InnoDB 实现了如下两种标准的行级锁:

共享锁(读锁 S Lock),允许事务读一行数据。

排它锁(写锁 X Lock),允许事务删除一行数据或者更新一行数据。

行级锁中,除了 S 和 S 兼容,其他都不兼容。

2、根据锁算法分类

不同隔离级别下,行级锁的算法是不同的。根据锁的算法不同,行锁又分为记录锁、间隙锁、临键锁。

在读已提交隔离级别下,行级锁的算法只有记录锁,也就是仅仅把一条记录锁上。

在可重复读隔离级别下,行级锁的算法除了有记录锁,还有间隙锁(目的是为了避免幻读),所以行级锁的算法主要有三类:

● Record Lock,记录锁,也就是仅仅把一条记录锁上;

● Gap Lock,间隙锁,锁定一个范围(前开后开),但是不包含记录本身;

● Next-Key Lock,下一键锁或临键锁,Record Lock + Gap Lock 的组合,锁定一个范围(前开后闭),并且锁定记录本身。主要解决的问题是 RR 隔离级别下的幻读。


表级锁

MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁。而表锁中,常见的有普通表锁、自增锁、意向锁等。

1、普通表锁

普通表锁的常见语法是 lock tables … read/write,用于显式指定对某个表进行加锁。

2、自增锁

主要用于事务中插入自增字段(AUTO_INCREAMENT),例如我们最常用的自增主键id。在最简单的情况下,如果一个事务正在向表中插入值,则任何其他事务都必须等待插入到该表中,以便第一个事务插入的行接收连续的主键值。

3、意向锁

为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁:

● 意向共享锁(读锁 IS Lock),事务想要获取一张表的几行数据的共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁。

● 意向排他锁(写锁 IX Lock),事务想要获取一张表中几行数据的排它锁,事务在给一个数据行加排它锁前必须先取得该表的 IX 锁。

首先解释一下意向锁,以下为意向锁的意图解释:

The main purpose of IX and IS locks is to show that someone is locking a row, or going to lock a row in the table.

加意向锁为了表明某个事务正在锁定一行或者将要锁定一行数据。

首先申请意向锁的动作是 InnoDB 完成的,怎么理解意向锁呢?例如:事务 A 要对一行记录 R 进行上 X 锁,那么 InnoDB 会先申请表的 IX 锁,再锁定记录 R 的 X 锁。

在事务 A 完成之前,事务 B 想要来个全表操作,此时直接在表级别的 IX 就告诉事务 B 需要等待而不需要在表上判断每一行是否有锁。

意向排它锁存在的价值在于节约 InnoDB 对于锁的定位和处理性能。另外注意了,除了全表扫描以外意向锁都不会阻塞。

4、元数据锁

元数据锁(metadata lock,MDL)在 MySQL 5.5 版本中引入的,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。


全局锁

全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL),此时整个库处于只读状态。

全局锁的典型使用场景是,做全库逻辑备份。


InnoDB行锁实现方式

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!(这个问题遇到过,由于没加索引,行锁变表锁)

● 在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。

● 由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。

● 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。

● 即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价来决定的,如果MySQL认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。



全文完,希望可以帮到正在阅读的你,如果觉得有帮助,可以分享给你身边的朋友,同事,你关心谁就分享给谁,一起学习共同进步~~~

❤ 欢迎关注我的公众号【凡尘读书楼】,一起学习新知识!
————————————————————————————
公众号:凡尘读书楼
墨天轮:https://www.modb.pro/u/399450
知识星球 :凡尘dba人生有限公司
————————————————————————————

最后修改时间:2024-07-07 19:13:59
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论