只执行
SELECT、INSERT、DELETE、UPDATE语句,不会有表级别的 S 锁或者 X 锁。
如果需要,可以使用LOCK TABLES来主动申请表级别的 S 锁或者 X 锁。
如果此时有DDL语句,那么就是增加MDL 锁。
表级 S、X 锁
在对某个表执行 SELECT、INSERT、DELETE、UPDATE 语句时,InnoDB 存储引擎是不会为这个表添加 表级别的 S 锁或者 X 锁 的。在对某个表执行一些诸如 ALTER TABLE 、 DROP TABLE 这类的 DDL 语句时,其他事务对这个表并发执行诸如 SELECT、INSERT、DELETE、UPDATE 的语句会发生阻塞。同理,某个事务中对某个表执行 SELECT、INSERT、DELETE、UPDATE 语句时,在其他会话中对这个表执行 DDL 语句也会发生阻塞。这个过程其实是通过在 server 层 使用一种称之为元数据锁(英文名: Metadata Locks ,简称 MDL )MDL 锁 结构来实现的。
一般情况下,不会使用 InnoDB 存储引擎提供的表级别的 S 锁和 X 锁。只会在一些特殊情况下,比方说 崩溃恢复 过程中用到。比如,在系统变量 autocommit=0, innodb_table_locks = 1 时,手动 获取 InnoDB 存储引擎提供的表 t 的 S 锁 或者 X 锁 可以这么写:
LOCK TABLES t READ:InnoDB 存储引擎会对表 t 加表级别的 S 锁。LOCK TABLES t WRITE:InnoDB 存储引擎会对表 t 加表级别的 X 锁。
不过尽量避免在使用 InnoDB 存储引擎的表上使用 LOCK TABLES 这样的手动锁表语句,它们并不会提供什么额外的保护,只是会降低并发能力而已。InnoDB 的厉害之处还是实现了更细粒度的 行锁,关于 InnoDB 表级别的 S 锁和 X 锁大家了解一下就可以了。 MySQL 的表级锁有两种模式:(以 MyISAM 表进行操作的演示)

LOCK TABLES 后需要使用 UNLOCK TABLES 进行锁的释放,使用 COMMIT 也不会释放锁。需要注意的是,UNLOCK TABLES 执行后会隐式的结束事务。
论是表级锁还是行级锁,都存在共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)这两类:
- 共享锁(S 锁):又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
- 排他锁(X 锁):又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条事务加任何类型的锁(锁不兼容)。
排他锁与任何的锁都不兼容,共享锁仅和共享锁兼容。
| - | S 锁 | X 锁 |
|---|---|---|
| S 锁 | 不冲突 | 冲突 |
| X 锁 | 冲突 | 冲突 |
由于 MVCC 的存在,对于一般的 SELECT 语句,InnoDB 不会加任何锁。不过, 你可以通过以下语句显式加共享锁或排他锁。
# 共享锁 可以在 MySQL 5.7 和 MySQL 8.0 中使用
SELECT ... LOCK IN SHARE MODE;
# 共享锁 可以在 MySQL 8.0 中使用
SELECT ... FOR SHARE;
# 排他锁
SELECT ... FOR UPDATE;