引言
大家在面试中有没遇到面试官问你下面六句Sql的区别呢
select * from table where id = ?
select * from table where id < ?
select * from table where id = ? lock in share mode
select * from table where id < ? lock in share mode
select * from table where id = ? for update
select * from table where id < ? for update
如果你能清楚的说出,这六句sql在不同的事务隔离级别下,是否加锁,加的是共享锁还是排他锁,是否存在间隙锁,那这篇文章就没有看的意义了。之所以写这篇文章是因为目前为止网上这方面的文章太片面,都只说了一半,且大多没指明隔离级别,以及where
后跟的是否为索引条件列。在此,我就不一一列举那些有误的文章了,大家可以自行百度一下,大多都是讲不清楚。OK,要回答这个问题,先问自己三个问题
- 当前事务隔离级别是什么
- id列是否存在索引
- 如果存在索引是聚簇索引还是非聚簇索引呢?
OK,开始回答
(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)
正文
- innodb一定存在聚簇索引,默认以主键作为聚簇索引
- 有几个索引,就有几棵B+树(不考虑hash索引的情形)
- 聚簇索引的叶子节点为磁盘上的真实数据。非聚簇索引的叶子节点还是索引,指向聚簇索引B+树。
下面啰嗦点基础知识
锁类型
共享锁(S锁):假设事务T1对数据A加上共享锁,那么事务T2可以读数据A,不能修改数据A。
排他锁(X锁):假设事务T1对数据A加上共享锁,那么事务T2不能读数据A,不能修改数据A。
我们通过update
、delete
等语句加上的锁都是行级别的锁。只有LOCK TABLE … READ
和LOCK TABLE … WRITE
才能申请表级别的锁。
意向共享锁(IS锁):一个事务在获取(任何一行/或者全表)S锁之前,一定会先在所在的表上加IS锁。
意向排他锁(IX锁):一个事务在获取(任何一行/或者全表)X锁之前,一定会先在所在的表上加IX锁。
意向锁存在的目的?
OK,这里说一下意向锁存在的目的。假设事务T1,用X锁来锁住了表上的几条记录,那么此时表上存在IX锁,即意向排他锁。那么此时事务T2要进行LOCK TABLE … WRITE
的表级别锁的请求,可以直接根据意向锁是否存在而判断是否有锁冲突。
加锁算法
我的说法是来自官方文档:
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html
加上自己矫揉造作的见解得出。
ok,记得如下三种,本文就够用了
Record Locks
:简单翻译为行锁吧。注意了,该锁是对索引记录进行加锁!锁是在加索引上而不是行上的。注意了,innodb
一定存在聚簇索引,因此行锁最终都会落到聚簇索引上!
Gap Locks
:简单翻译为间隙锁,是对索引的间隙加锁,其目的只有一个,防止其他事物插入数据。在Read Committed
隔离级别下,不会使用间隙锁。这里我对官网补充一下,隔离级别比Read Committed
低的情况下,也不会使用间隙锁,如隔离级别为Read Uncommited
时,也不存在间隙锁。当隔离级别为Repeatable Read
和Serializable
时,就会存在间隙锁。
Next-Key Locks
:这个理解为Record Lock+
索引前面的Gap Lock
。记住了,锁住的是索引前面的间隙!比如一个索引包含值,10,11,13和20。那么,间隙锁的范围如下
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)