接上文https://juejin.cn/post/6844904021522645000
前言
与其说是博客,不如说是翻译。
这里只写常用crud语句的部分,复杂语句请参考官方文档。
锁的设置
锁定读、修改、删除通常在sql执行的过程中为扫描到的记录加上锁,他并不在乎where里的条件,而只在乎扫描到的范围。他们通常用的是next-key锁(即记录锁与gap锁的结合)。
如果锁是排他锁,且用到了二级索引,那么innodb会回表并在聚簇索引上设置锁。
如果sql没有合适的索引,那么就必须扫描全表,扫描的时候会把扫描到的每一行都加上锁。(我以前觉得for update有索引就是行锁,没索引就是表锁,这个想法不对啊,汗颜)
SELECT ... FROM
一致性读,没锁,也不管锁,利用mvcc读取记录。
SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE
为扫描到的行加锁,之后再对不符合条件的记录解锁(例如where)
- SELECT ... LOCK IN SHARE MODE
- 为搜索遇到的记录加上共享next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。
- SELECT ... FOR UPDATE
- 为搜索遇到的记录加上排他next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。
for update阻塞了 share mode读,而一致性读不在乎锁,有mvcc,该读照读。(如果本事务中执行过update,那么再select会读到之前不存在的记录,即使在可重复读中也如此,版本链的关系)
UPDATE ... WHERE
为搜索遇到的记录加上排他next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。
当修改主键索引时,也给受影响的二级索引记录加锁。
DELETE FROM ... WHERE
为搜索遇到的记录加上排他next-key锁。如果是唯一索引搜索唯一行的情况下,只为记录加上Record锁。
INSERT
在被插入的行上设置排他锁,这个锁时index-record锁,并不阻止其他事务往这个gap里这条被插入事务之前插入。
插入数据前,设置一个插入意向锁。假如有4,7的数据,两个想要插入5,6的事务均会索引4和7之间的gap,然后获取被插入行的排他锁,因为行不冲突,两个事务互相不阻塞。
如果插入的行冲突了,重复行会被设置共享锁,可能会有死锁隐患。
附注
官方文档真是好东西