只执行 SELECTINSERTDELETEUPDATE 语句,不会有表级别的 S 锁或者 X 锁。
如果需要,可以使用 LOCK TABLES 来主动申请表级别的 S 锁或者 X 锁。
如果此时有 DDL 语句,那么就是增加 MDL 锁

表级 S、X 锁

在对某个表执行 SELECTINSERTDELETEUPDATE 语句时,InnoDB 存储引擎是不会为这个表添加 表级别的 S 锁或者 X 锁 的。在对某个表执行一些诸如 ALTER TABLEDROP TABLE 这类的 DDL 语句时,其他事务对这个表并发执行诸如 SELECTINSERTDELETEUPDATE 的语句会发生阻塞。同理,某个事务中对某个表执行 SELECTINSERTDELETEUPDATE 语句时,在其他会话中对这个表执行 DDL 语句也会发生阻塞。这个过程其实是通过在 server 层 使用一种称之为元数据锁(英文名: Metadata Locks ,简称 MDLMDL 锁 结构来实现的。

一般情况下,不会使用 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 表进行操作的演示)

500|600

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;