InnoDB 锁

共享锁(S)与排他锁(X)

InnoDB 实现了标准的行级锁定(行锁),包含两种类型的锁:共享锁(S)和独占锁(X)

  • 共享锁(S):Shared Lock,也称读锁、S lock,其他会话事务也能获得该行上的共享锁(S),但不能获得排他锁(X)。那么其他事务就无法更新、删除该行。
  • 排他锁(X):Exclusive Lock,也称写锁、独占锁、X lock,其他会话事务不能获得该行上的任意类型的锁(S 或 X)。可保证同一时刻只有一个会话事务可以更新或删除数据。

如果事务 A 在表 t 的第 r 行记录上持有一个共享锁(S),那么事务 B 也可立即持有第 r 行上的 S 锁,但无法立即持有第 r 行上的 X 锁。

如果事务 A 在表 t 的第 r 行记录上持有一个排他锁(X),那么事务 B 无法立即持有第 r 行上任意类型的锁(S 或 X)。不得不等待事务 A 释放锁。

可归纳总结为:

  • 共享锁(S)与 共享锁(S)兼容;
  • 共享锁(S)与 排他锁(X)冲突;
  • 排他锁(X)与 共享锁(S)、排他锁(X)冲突;

事务中的锁释放的方式有以下几种:

  • 事务执行完毕,提交(commit)或回滚(rollback)。单条 SQL 语句也是事务,只不过它是自动提交的。
  • 事务所在的会话连接(线程)被杀死。
  • 被当前会话连接中的其他事务所覆盖。
  • 服务器宕机。

UPDATE、DELETE、INSERT 语句,会自动先获取排他锁(X)
普通的 SELECT 语句和锁无关。

但是,可以手动给 SELECT 查询语句加锁

  • 手动加共享锁(Sselect ... lock in share mode
  • 手动加排他锁(X) select ...for update

为了便于说明,先创建测试数据。

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` char(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '用户名称',
  `department_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户所属的部门id',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '用户的状态: 1启用,2禁用',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `department_id_index` (`department_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用户表';

# 插入部分测试数据
INSERT `user` (`id`, `name`, `department_id`, `status`) VALUES 
('2', 'test', '1', '1'),
('3', 'test', '8', '1'),
('4', 'test', '8', '1'),
('5', 'test', '2', '1'),
('7', 'test', '2', '1'),
('8', 'test', '2', '1'),
('9', 'test', '8', '1'),
('11', 'test', '2', '1'),
('13', 'test', '5', '1'),
('15', 'test', '5', '1');

说明: 以下示例分析,采用的是 MySQL 5.7,但在 MySQL 8.0 中会有一点点区别。

共享锁(S)

事务 A 在某一行持有共享锁(S),对其他事务的影响如下:

  • 不能获得该行的排他锁(X),自然就不能更新、删除数据。
  • 可以获得该行的共享锁(S),select ... lock in share mode
  • 可以进行普通的 select 查询。

注意: 如果事务 A 在某一行持有共享锁,之后,其他事务也获得该行的共享锁,事务 A 再来更新该行时,就会出现无法更新的情况。

示例 1

事务 A 在获取了某一行的共享锁后,其他事务无法获取该行的排他锁。

在第一个会话连接里,开启事务 A,并给 id=3 的行上加共享锁(S)。先不提交事务。

BEGIN;
SELECT * FROM `user` WHERE id=3 LOCK IN SHARE MODE;

然后,在第二个会话连接里,执行事务 B,对 id=3 的行进行更新。

UPDATE `user` SET department_id=5 WHERE id=3;

可以发现,事务 B 阻塞了,迟迟无法自动提交。

这时,在第三个会话连接里,立即通过下面的 SQL 查看锁的争用信息。

# 查看当前的锁争用信息
SELECT 
	trx_id,trx_state,trx_rows_locked,trx_started,trx_wait_started,trx_mysql_thread_id,
	lock_mode,lock_type,lock_table,lock_index,trx_query
FROM information_schema.innodb_trx as trx
JOIN information_schema.innodb_locks as lk ON trx.trx_id=lk.lock_trx_id;
+-----------------+-----------+-----------------+---------------------+---------------------+---------------------+-----------+-----------+---------------+------------+----------------------------------------------+
| trx_id          | trx_state | trx_rows_locked | trx_started         | trx_wait_started    | trx_mysql_thread_id | lock_mode | lock_type | lock_table    | lock_index | trx_query                                    |
+-----------------+-----------+-----------------+---------------------+---------------------+---------------------+-----------+-----------+---------------+------------+----------------------------------------------+
| 3370            | LOCK WAIT |               1 | 2023-02-27 17:13:33 | 2023-02-27 17:13:33 |                  21 | X         | RECORD    | `test`.`user` | PRIMARY    | UPDATE `user` SET department_id=5 WHERE id=3 |
| 283345581937264 | RUNNING   |               1 | 2023-02-27 16:42:02 | NULL                |                  22 | S         | RECORD    | `test`.`user` | PRIMARY    | NULL                                         |
+-----------------+-----------+-----------------+---------------------+---------------------+---------------------+-----------+-----------+---------------+------------+----------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

事务 A 的事务 id 是 283345581937264 ,事务状态是运行中,锁定了一行,锁类型是 S,线程 id(即连接 id) 是 22。

事务 B 的事务 id 是 3370 ,事务状态是锁等待,等待获取的锁类型 X,线程 id(即连接 id) 是 21。

大概 50 秒后,事务 B 就会超时(锁等待超时),并报错:

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

但是,事务 A 因为它自身已经获取到了共享锁(S),并不是锁等待(LOCK WAIT)状态,所以不会超时,可一直处于 RUNNING 运行中状态,直到手动提交或回滚,它才会释放锁。

通过 information_shcema 中的 innodb_trx、innodb_locks、innodb_lock_waits、processlist 表可以跟进监控当前事务并且分析存在的问题。

注意:从 MySQL 8.0 开始,data_locks 取代了 innodb_locks,data_lock_waits 取代了 innodb_lock_waits。

排他锁(X)

事务 A 在某一行持有排他锁(X),对其他事务的影响如下:

  • 不能获得该行的排他锁(X),select ... for update自然就不能更新、删除数据。
  • 不能获得该行的共享锁(S),select ... lock in share mode
  • 可以进行普通的 select 查询。
示例 2

事务 A 在获取了某一行的排他锁后,其他事务无法获取该行的排他锁。

在第一个会话连接里,开启事务 A,并给 id=3 的行上加排他锁(X)。先不提交事务。

BEGIN;
SELECT * FROM `user` WHERE id=3 for update;

# 下面的语句也是同样的效果——排他锁(X)
# UPDATE `user` SET department_id=1 WHERE id=3;

然后,在第二个会话连接里,执行事务 B,对 id=3 的行进行更新。

UPDATE `user` SET department_id=2 WHERE id=3;

可以发现,事务 B 阻塞了,迟迟无法自动提交。

这时,在第三个会话连接里,立即通过下面的 SQL 查看锁的争用信息。

SELECT 
	trx_id,trx_state,trx_rows_locked,trx_started,trx_wait_started,trx_mysql_thread_id,
	lock_mode,lock_type,lock_table,lock_index,trx_query
FROM information_schema.innodb_trx as trx
LEFT JOIN information_schema.innodb_locks as lk ON trx.trx_id=lk.lock_trx_id;
+--------+-----------+-----------------+---------------------+---------------------+---------------------+-----------+-----------+---------------+------------+----------------------------------------------+
| trx_id | trx_state | trx_rows_locked | trx_started         | trx_wait_started    | trx_mysql_thread_id | lock_mode | lock_type | lock_table    | lock_index | trx_query                                    |
+--------+-----------+-----------------+---------------------+---------------------+---------------------+-----------+-----------+---------------+------------+----------------------------------------------+
| 3397   | LOCK WAIT |               1 | 2023-02-27 20:25:31 | 2023-02-27 20:25:31 |                  24 | X         | RECORD    | `test`.`user` | PRIMARY    | UPDATE `user` SET department_id=2 WHERE id=3 |
| 3396   | RUNNING   |               1 | 2023-02-27 20:24:06 | NULL                |                  26 | X         | RECORD    | `test`.`user` | PRIMARY    | NULL                                         |
+--------+-----------+-----------------+---------------------+---------------------+---------------------+-----------+-----------+---------------+------------+----------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

大概 50 秒后,事务 B 就会超时(锁等待超时),并报错:

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

意向锁(Intention Lock)

InnoDB 支持多粒度锁(锁粒度可分为行锁和表锁),允许行锁和表锁共存。

例如:LOCK TABLES ... WRITE 语句会获得指定表的独占锁(X),为了实现多粒度的锁定,InnoDB 采用了意向锁。

意向锁是表级别的锁定。它表明稍后表中的行将需要哪种类型的锁(共享锁 S 或 独占锁 X)。

先提前声明一个意向,获取表级别的意向锁(IS 或 IX),如果获取成功,稍后就对该表的某行加对应的锁(S 或 X)。
这样,就实现了表级别的意向锁和行锁的共存。

意向锁分为两种类型:

  • 意向共享锁(IS):先设置表锁 IS,再设置行锁 S。
  • 意向独占锁(IX):先设置表锁 IX,再设置行锁 X。
# 先获取表锁 IS,再获取行锁 S
SELECT ... LOCK IN SHARE MODE

# 先获取表锁 IX,再获取行锁 X
SELECT ... FOR UPDATE
  • 在事务获取表中某一行的 S 锁之前,它会先获取该表的 IS 锁。
  • 在事务获取表中某一行的 X 锁之前,它会先获取该表的 IX 锁。

意向锁的注意事项:

  • 意向锁是表级别的锁,它是由 InnoDB 自动维护(设置)的。
  • 意向锁不会与行级别的共享锁(S)和排他锁(X)冲突
  • 处理行锁之间的影响时,不用考虑意向锁,只需考虑行级别的 S 和 X,以及表级别的 S 和 X(如果有的话)。

意向锁与其他表锁的兼容性

意向锁与其他表锁的兼容性关系矩阵如下:

锁类型 | X | IX | S | IS
—|—|—|—|—|—
X | 冲突 | 冲突 | 冲突 | 冲突
IX | 冲突 | 兼容 | 冲突 | 兼容
S | 冲突 | 冲突 | 兼容 | 兼容
IS | 冲突 | 兼容 | 兼容 | 兼容

  • 意向锁之间彼此兼容
  • 表级别的 X 与 IS、IX 互斥
  • 表级别的 S 与 IX 互斥

事务中请求获取锁时,如果该锁和另一个已存在的锁兼容,则获取成功;如果冲突,则获取失败,事务将等待,直到冲突的锁被释放。

如果获取锁的请求和已存在的锁冲突,并由于死锁导致一直获取不到锁,就会产生错误。

意向锁不会阻塞除了全表请求(如 LOCK TABLES ... WRITE)之外的任何东西。它不会对行锁有影响。

SHOW ENGINE INNODB STATUS\G的输出中,可以看到意向锁的数据情况:

TABLE LOCK table `test`.`t` trx id 10080 lock mode IX

意向锁的作用

意向锁存在的作用是提前告知其他表锁,其他的表锁需要先获取更弱的 IS、IX 锁,如果获取失败就没有必要花大开销检查每一行是否有 S、X 锁。

示例 3

在第一个会话连接里,开启事务 A,并给 id=3 的行上加排他锁(X)。先不提交事务。

BEGIN;
SELECT * FROM `user` WHERE id=3 for update;

此时,user 表上有一个行锁 X 和一个表级锁 IX。

然后,在第二个会话连接里,执行全表读锁(S)请求。

LOCK TABLES user READ;

这个全表读锁(S)请求,就可以先去与表级别的意向锁 IX 比较兼容性,发现不兼容,直接阻塞。从而,省去了检查每一行的行锁的复杂开销。

行锁(Record Lock)

行锁指的是某一行的索引记录上的锁定。

例如,SELECT * FROM user WHERE department_id = 1 FOR UPDATE 会对 department_id = 1 的行(可能是多行)的索引记录上设置排他锁(X)。

行锁总是对行的索引记录加锁。

如果表没有显式地声明任何索引,对于这种情况,InnoDB 会自行创建一个隐式的聚簇索引,然后在聚簇索引上设置行锁。

当搜索或扫描表的索引时,对扫描的记录行设置共享锁(S) 或排他锁(X)。行锁实际上是索引记录锁定。

SELECT * FROM user WHERE department_id = 1 FOR UPDATE 为例:

  • 如果 where 条件有使用到索引,那么仅对 where 匹配到的行加锁。
  • 如果 where 条件没有使用到索引,那么会对该表的所有行加锁。

同样的,UPDATE user SET status=1 WHERE department_id=1 语句,也会因 where 条件是否使用到索引,锁定的行数也不相同。

行锁就是上面说到的行级别的共享锁(S)和排他锁(X)。

  • 行锁(S):是行级别的共享锁(S),它与其他事务同一行上的行锁(X)冲突。
  • 行锁(X):是行级别的排他锁(X),它与其他事务同一行上的行锁(S)、行锁(X)都会冲突。

示例 4

在第一个会话连接里,开启事务 A。

# 仅仅是开启事务,不进行提交
START TRANSACTION;
UPDATE user SET `status`=2 WHERE department_id=8;

在第二个会话连接里,通过 Explain 分析上述 SQL,判断其是否有用到索引及实际扫描的行数。

EXPLAIN UPDATE user SET `status`=2 WHERE department_id=8;

分析结果如下:

+----+-------------+-------+------------+-------+---------------------+---------------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys       | key                 | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------------+---------------------+---------+-------+------+----------+-------------+
|  1 | UPDATE      | user  | NULL       | range | department_id_index | department_id_index | 4       | const |    3 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------------+---------------------+---------+-------+------+----------+-------------+
1 row in set (0.00 sec)

可以推断,上述事务 A 中的 SQL 用到了索引 department_id_index,实际扫描的行数为 3。那么,这 3 条记录就会持有行锁(X)。

然后,在第二个会话连接里,执行事务 B。

UPDATE user SET `status`=2 WHERE id=3;

在第三个会话连接里,用下面的 SQL 查看事务中锁的争用情况。

SELECT 
	trx_id,trx_state,trx_started,trx_wait_started,trx_mysql_thread_id,
	lock_mode,lock_rec,lock_type,lock_table,lock_index,trx_query
FROM information_schema.innodb_trx as trx
LEFT JOIN information_schema.innodb_locks as lk ON trx.trx_id=lk.lock_trx_id;
+--------+-----------+---------------------+---------------------+---------------------+-----------+----------+-----------+---------------+------------+---------------------------------------+
| trx_id | trx_state | trx_started         | trx_wait_started    | trx_mysql_thread_id | lock_mode | lock_rec | lock_type | lock_table    | lock_index | trx_query                             |
+--------+-----------+---------------------+---------------------+---------------------+-----------+----------+-----------+---------------+------------+---------------------------------------+
| 3429   | LOCK WAIT | 2023-02-27 23:09:17 | 2023-02-27 23:09:17 |                  31 | X         |        3 | RECORD    | `test`.`user` | PRIMARY    | UPDATE user SET `status`=2 WHERE id=3 |
| 3426   | RUNNING   | 2023-02-27 23:08:11 | NULL                |                  26 | X         |        3 | RECORD    | `test`.`user` | PRIMARY    | NULL                                  |
+--------+-----------+---------------------+---------------------+---------------------+-----------+----------+-----------+---------------+------------+---------------------------------------+
2 rows in set, 1 warning (0.00 sec)

事务 B 的更新 SQL 处于 LOCK WAIT (锁等待)状态。原因是因为事务 A 已经持有了 id=3 行上的排他锁(X)。其他的会话连接如果也想持有该记录的排他锁,就必须等待事务 A 释放锁。

一旦超过锁等待超时时间,上述 SQL 就会报错。

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

这就是常见的【锁等待超时】问题。

间隙锁(Gap Lock)

间隙锁指的是多个索引记录之间的间隙、第一个索引记录之前的间隙或最后一个索引记录之后的间隙上的锁定。

间隙锁锁定的是表中并不存在的记录,是间隙。锁定的是一个开区间。

  • Gap S:间隙共享锁,与其他事务在间隙中插入不存在的记录会冲突。
  • Gap X:间隙独占锁,与其他事务在间隙中插入不存在的记录会冲突。

注意事项:

  • 间隙锁锁定的是空隙(不存在的记录),与其他事务在间隙中插入记录会冲突。
  • 间隙锁之间可以共存。
  • SELECT ... LOCK IN SHARE MODE 查询语句的 where 条件就算是等值查询,如果没有用到索引,也会产生间隙锁。
  • SELECT ... FOR UPDATE 查询语句的 where 条件就算是等值查询,如果没有用到索引,也会产生间隙锁。
  • update、delete 语句的 where 条件,如果没有用到索引,也会产生间隙锁。
  • 间隙锁用于某些特定的事务隔离级别(如 REPEATABLE-READ),主要是为了解决幻读的问题。

说明: 使用唯一索引搜索唯一行的 SQL,不产生间隙锁(不包含复合唯一索引)。

例如: SELECT * FROM user WHERE id=2 FOR UPDATE 只会产生行锁 X。

示例 5

在第一个会话连接中,开启事务 A。

BEGIN;
SELECT * FROM user WHERE id>11 FOR UPDATE;

在第二个会话连接中,执行事务 B,插入 id = 12 的记录。

INSERT `user` (`id`, `name`) VALUES ('12', 'a');

可以发现,事务 B 阻塞了。一段时间后,就会超时报错。

[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

在第三个会话连接中,分析锁争用的信息。

SELECT 
	trx_id,trx_state,trx_started,trx_wait_started,trx_mysql_thread_id,
	lock_mode,lock_type,lock_rec,lock_data,lock_table,lock_index,trx_query
FROM information_schema.innodb_trx as trx
LEFT JOIN information_schema.innodb_locks as lk ON trx.trx_id=lk.lock_trx_id;
+--------+-----------+---------------------+---------------------+---------------------+-----------+-----------+----------+-----------+---------------+------------+-------------------------------------------------+
| trx_id | trx_state | trx_started         | trx_wait_started    | trx_mysql_thread_id | lock_mode | lock_type | lock_rec | lock_data | lock_table    | lock_index | trx_query                                       |
+--------+-----------+---------------------+---------------------+---------------------+-----------+-----------+----------+-----------+---------------+------------+-------------------------------------------------+
| 3462   | LOCK WAIT | 2023-02-28 00:38:43 | 2023-02-28 00:38:43 |                  35 | X,GAP     | RECORD    |       10 | 13        | `test`.`user` | PRIMARY    | INSERT `user` (`id`, `name`) VALUES ('12', 'a') |
| 3445   | RUNNING   | 2023-02-28 00:20:12 | NULL                |                  26 | X         | RECORD    |       10 | 13        | `test`.`user` | PRIMARY    | NULL                                            |
+--------+-----------+---------------------+---------------------+---------------------+-----------+-----------+----------+-----------+---------------+------------+-------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

分析说明:

  • 在 id 值为 13、15 的记录上设置了行锁(X),其他会话的事务无法对其进行更新或删除操作。
  • 在 id 值范围为 (11, 13)、(13, 15)、(15, +∞) 的间隙设置了间隙锁(Gap),其他的事务无法在间隙锁中插入记录。如果 id=11 的记录不存在,那么该位置也会有间隙锁。
  • 间隙锁解决了幻读的问题。

Next-Key Lock

Next-Key Lock:是行锁和间隙锁的组合。Next-Key Lock = Record Lock + Gap Lock。

Next-Key 锁可避免其他会话事务在行锁和间隙锁中更新或插入记录,可解决幻读的问题。

Next-Key 锁是为了防止发生幻读,而只有 repeatable-read 及以上隔离级别才能防止幻读。也就是说,其他的隔离级别不存在 Next-Key 这一说法。

Next-Key 锁的实现原理是当扫描索引记录时,不仅会对扫描的索引记录加行锁(Record Lock),还会对扫描的空隙加间隙锁(Gap Lock)。

注意: 对于唯一索引的等值 where 条件操作(UPDATE、DELETE、LOCK IN SHARE MODE、FOR UPDATE),只会产生唯一的行锁,不会产生 Next-Key 锁。

其实,上面的【示例 5 】中,就有 Next-Key 锁。

但是,并不是所有的范围 where 条件都会产生 Next-Key。需要结合实际情况进行分析。

Insert Intention Lock

插入意向锁(Insert Intention Lock)是指在插入记录之前由 insert 操作产生的一种间隙锁。

多个事务朝间隙中的不同位置插入数据,并不会冲突,只会产生插入意向锁。

  • 插入意向锁和其他事务在同一位置处的间隙锁冲突。
  • 插入意向锁和其他事务在同一位置处的插入间隙锁冲突。

AUTO-INC Lock

自增锁(AUTO-INC Lock)是一种特殊的表级别的锁,当向带有自增列(AUTO_INCREMENT)的表中插入数据时,会加 AUTO-INC Lock。

AUTO-INC Lock 用于自增列插入数据时使用。 插入数据时,先在表上设置 AUTO-INC Lock,然后为自增列分配递增的值,插入操作完成之后,再释放锁。

可以想象,这种表级别的自增锁,会严重影响并发插入的性能。

后来,引入了轻量级的 mutex 互斥锁,它的性能高于 Auto-Inc Lock,因为 Auto-Inc Lock 是在插入完成之后才释放锁,而 mutex 是在插入时,一旦确定并分配好了自增值,就会立马释放锁。

  • 自增锁(AUTO-INC Lock)会阻塞其他事务的插入操作。
  • 轻量级的 mutex 互斥锁 不会阻塞其他事务的插入操作。

注意: 如果你的插入语句,明确指定了自增列的值,就不用考虑自增锁。

自增锁的模式 innodb_autoinc_lock_mode 变量控制了自增锁的运算法则,它让你可以在可预测的顺序自增值和插入操作的最大并发之间进行权衡。

innodb_autoinc_lock_mode 的值有三种情况:

  • 0 传统模式(Traditional)任何类型的 insert 语句,都采用自增锁。其他事务的 insert 操作必须等待自增锁的释放。可保证单个 insert 语句内生成连续的自增值。并发性能低。
  • 1 连续模式(Consecutive),MySQL 8.0 之前版本的默认模式。对于简单的能够提前确定行数的 insert 语句,采用的是 mutex 锁;而对于插入行数不确定的 insert 语句(如 insert … select …),仍然采用自增锁。这样,即使是 statement-based 方式的 binlog 主从复制也是安全的。
  • 2 交叉模式(Interleaved),MySQL 8.0 的默认模式。任何类型的 insert 语句都采用轻量级的 mutex 锁,多条 insert 语句可并发执行。并发性能最好。

交叉模式的副作用是单个 insert 的自增值并不连续,因为自增值的分配会在多个 insert 语句中来回交叉的执行。

如果 mysql 主从复制的 binlog 日志,采用的是 statement-based(基于语句的)方式,就会导致主从数据的不一致。也就是说,对于同一条数据,主库和从库的自增id 的值不一样。这是非常严重的问题!

好在 MySQL 8.0 的 binlog 日志文件的默认存储格式从 statement-based 方式切换到了 row-based(基于真实的数据行,自增 id 是确定的)方式。这样,就可以把自增锁的模式参数 innodb_autoinc_lock_mode 调整为 2(交叉模式)。

Predicate Lock

谓词锁(Predicate Lock)可以处理 InnoDB 空间索引数据的锁定。

InnoDB 可以支持多维度的空间数据,对于这类空间数据,Next-Key Lock 就不好应对了。因此 InnoDB 采用 Predicate Lock 来支持具有空间索引(Spatial Index)的数据表的隔离级别。

空间索引数据包含最小边界矩形 minimum bounding rectangle(MBR)值,因此 InnodB 通过在用于查询的 MBR 值上设置谓词锁,其他事务就无法插入或修改与查询条件匹配的行。从而使 InnoDB 在索引上实现一致性读。

通常,谓词锁(Predicate Lock)极少遇见,了解即可。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值