引入记录锁,间隙锁,临键锁的目的是为了干嘛?是为了解决幻读问题,也就是防止一个事务A在查询的时候,另一个事务B在它查询的区间内插入,删除,修改数据,导致事务A前后查询到的行数不一致(比如之前查到的是5行,现在查到了7行数据)。知道了这个最根本目的,就可以分析出到底锁的是哪个区间,而不用去记什么时候间隙锁,临键锁。
比如:
1.id是主键索引(主键索引是唯一索引),执行
SELECT * FROM `test` WHERE `id`=1 FOR UPDATE;
显然你只需要锁住id=1这一行记录即可,因为id这一列是主键索引,这样其它行的id是无法修改成id=1的,因此加的是行级锁
2.
id是主键索引,SELECT * FROM users WHERE id = 4 FOR UPDATE;由于没有这条数据,所以这样会加间隙锁,对(3,5)这个区间上锁(因为如果你不对这个区间加上间隙锁,那如果别的事务插入了一条id=4的记录,就会影响我们的查询结果(本来是0,插入了结果就是1了))因此加的是间隙锁
3.
age这一列只是普通索引,而不是唯一索引
这张表B+树的叶子节点之间的关系如下:
你要防止24这条记录以前的记录被修改成24,也要防止32这条记录被修改成24,也要其他事务先在(24,32)区间内插入一条数据,再将这条数据的age改成24,由于age是非唯一索引,所以可以出现多行的age都是24,因此需要锁住的区间是(10,32),这个可以拆分成(10,24]一个临键锁+(24,32)一个间隙锁
总之,记住这些行锁的目的就是解决幻读问题,锁住区间,就可以依此判断出是对哪个区间进行加锁。而不用记什么到底是加记录锁还是临键锁还是间隙锁了。