You are viewing an old version of this page. View the current version.
Compare with Current View Page History
« Previous Version 3 Current »
锁是一种常见的并发事务的控制方式。
MyISAM 仅仅支持表级锁(table-level locking),一锁就锁整张表,这在并发写的情况下性非常差。InnoDB 不光支持表级锁(table-level locking),还支持行级锁(row-level locking),默认为行级锁。
行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。
表级锁和行级锁对比:
InnoDB 的行锁是针对索引字段加的锁,表级锁是针对非索引字段加的锁。当我们执行 UPDATE、DELETE 语句时,如果 WHERE条件中字段没有命中唯一索引或者索引失效的话,就会导致扫描全表对表中的所有行记录进行加锁。这个在我们日常工作开发中经常会遇到,一定要多多注意!!!
UPDATE
DELETE
WHERE
不过,很多时候即使用了索引也有可能会走全表扫描,这是因为 MySQL 优化器的原因。
InnoDB 行锁是通过对索引数据页上的记录加锁实现的,MySQL InnoDB 支持三种行锁定方式:
在 InnoDB 默认的隔离级别 REPEATABLE-READ 下,行锁默认使用的是 Next-Key Lock。但是,如果操作的索引是唯一索引或主键,InnoDB 会对 Next-Key Lock 进行优化,将其降级为 Record Lock,即仅锁住索引本身,而不是范围。
一些大厂面试中可能会问到 Next-Key Lock 的加锁范围,这里推荐一篇文章:MySQL next-key lock 加锁范围是什么? - 程序员小航 - 2021。
不论是表级锁还是行级锁,都存在共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)这两类:
排他锁与任何的锁都不兼容,共享锁仅和共享锁兼容。
由于 MVCC 的存在,对于一般的 SELECT 语句,InnoDB 不会加任何锁。不过, 你可以通过以下语句显式加共享锁或排他锁。
SELECT
# 共享锁 可以在 MySQL 5.7 和 MySQL 8.0 中使用 SELECT ... LOCK IN SHARE MODE; # 共享锁 可以在 MySQL 8.0 中使用 SELECT ... FOR SHARE; # 排他锁 SELECT ... FOR UPDATE;
如果需要用到表锁的话,如何判断表中的记录没有行锁呢,一行一行遍历肯定是不行,性能太差。我们需要用到一个叫做意向锁的东东来快速判断是否可以对某个表使用表锁。
意向锁是表级锁,共有两种:
意向锁是由数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享/排他锁之前,InnoDB 会先获取该数据行所在在数据表的对应意向锁。
意向锁之间是互相兼容的。
意向锁和共享锁和排它锁互斥(这里指的是表级别的共享锁和排他锁,意向锁不会与行级的共享锁和排他锁互斥)。