MySQL 中,SELECT ... FOR UPDATE
在 MySQL 中,SELECT ... FOR UPDATE
语句会对查询结果集中的行加排他锁(X 锁)。关于其他事务是否能读取当前行,以下是详细说明:
1. 排他锁(X 锁)的特性
- 排他锁是一种独占锁,加锁后:
- 其他事务无法对相同的行加任何类型的锁(包括共享锁和排他锁)。
- 其他事务无法修改或删除被锁定的行。
- 读取行为:
- 在默认的隔离级别(
REPEATABLE READ
或READ COMMITTED
)下,其他事务可以读取被锁定的行,但读取的是锁之前的快照数据(即不加锁的读取)。 - 在
READ UNCOMMITTED
隔离级别下,其他事务可以读取未提交的数据。
- 在默认的隔离级别(
2. 不同隔离级别下的行为
(1) READ UNCOMMITTED
- 其他事务可以读取被锁定的行,甚至可能读取到未提交的数据(“脏读”)。
(2) READ COMMITTED
- 其他事务可以读取被锁定的行,但读取的是锁之前的已提交数据(快照数据)。
(3) REPEATABLE READ
(MySQL 默认隔离级别)
- 其他事务可以读取被锁定的行,但读取的是事务开始时的快照数据。
(4) SERIALIZABLE
- 其他事务无法读取被锁定的行,直到锁被释放。
3. 示例
假设有两个事务:事务 A 和事务 B。
-
事务 A 执行:
START TRANSACTION; SELECT * FROM users WHERE id = 1 FOR UPDATE;
此时,事务 A 对
id = 1
的行加了排他锁。 -
事务 B 尝试读取:
START TRANSACTION; SELECT * FROM users WHERE id = 1;
在默认的
REPEATABLE READ
隔离级别下,事务 B 可以读取id = 1
的行,但读取的是事务 A 加锁之前的快照数据。
4. 总结
SELECT ... FOR UPDATE
会对查询结果集中的行加排他锁(X 锁)。- 其他事务是否能读取当前行:
- 在
READ UNCOMMITTED
、READ COMMITTED
和REPEATABLE READ
隔离级别下,其他事务可以读取被锁定的行,但读取的是快照数据。 - 在
SERIALIZABLE
隔离级别下,其他事务无法读取被锁定的行,直到锁被释放。
- 在
因此,SELECT ... FOR UPDATE
主要用于防止其他事务修改或删除被锁定的行,但通常不会阻止其他事务读取快照数据。