SELECT FOR UPDATE
是 MySQL 中实现悲观锁的核心机制,用于在高并发事务场景下保证数据的一致性和完整性。深入理解其原理和应用至关重要。
一、 核心概念与基础
-
作用:
-
在事务中锁定查询结果集(行或间隙),阻止其他事务对这些数据进行修改 (
UPDATE
/DELETE
) 或执行加锁读 (SELECT FOR UPDATE
/SELECT FOR SHARE
),直到当前事务提交 (COMMIT
) 或回滚 (ROLLBACK
)。 -
确保在事务执行期间,被锁定的数据不会被其他并发事务改变,常用于先读后写的场景(如库存扣减、账户转账、订单状态变更)。
-
-
语法:
SELECT column1, column2, ... FROM table_name [WHERE condition] [FOR UPDATE [OF column_list] [NOWAIT | SKIP LOCKED]]; -- MySQL 8.0+ 支持 NOWAIT/SKIP LOCKED
-
事务要求:
-
SELECT FOR UPDATE
必须在一个显式事务 (BEGIN
/START TRANSACTION
...COMMIT
/ROLLBACK
) 中执行。在自动提交 (autocommit=1
) 模式下单独执行,锁会立即释放,失去意义。
-
-
锁类型:
-
默认情况下,在
REPEATABLE READ
(RR) 隔离级别下,SELECT FOR UPDATE
会对符合条件的记录加 Next-Key Locks(记录锁 + 间隙锁)。 -
在
READ COMMITTED
(RC) 隔离级别下,通常只加 Record Locks(记录锁),不加间隙锁(Gap Locks)。但某些情况下(如唯一索引等值查询且记录存在时)也可能只加记录锁。 -
如果查询无法使用索引(全表扫描),会锁住整个表或所有扫描到的记录(非常危险!)。
-
二、 锁的范围与行为(关键面试点)
锁的具体范围取决于 WHERE 条件、使用的索引 和 事务隔离级别:
-
主键/唯一索引等值查询 (RR & RC):
-
记录存在: 加 Record Lock (记录锁) 在对应的行上。
-
记录不存在: 加 Gap Lock (间隙锁) 在值所在的间隙上(RR 级别特有ÿ
-