SELECT … FOR UPDATE 详解
SELECT ... FOR UPDATE 是 SQL 中的一个重要语句,主要用于实现行级锁定机制。下面我将详细介绍它的工作原理和使用场景。
基本概念
SELECT ... FOR UPDATE 是一种悲观锁的实现方式,它会在查询数据的同时对选中的行加上排他锁(exclusive lock),直到当前事务结束(提交或回滚)才会释放。
工作原理
- 锁定行为:当执行
SELECT ... FOR UPDATE时,数据库会锁定满足条件的行,防止其他事务修改或删除这些行 - 锁范围:通常锁定的是索引记录,如果没有索引可能会导致表锁
- 锁释放:锁会在事务结束时自动释放
基本语法
START TRANSACTION;
SELECT * FROM table_name WHERE condition FOR UPDATE;
-- 执行更新操作
UPDATE table_name SET column = value WHERE condition;
COMMIT;
使用场景
- 防止丢失更新:当多个事务同时读取-修改-写入同一数据时
- 库存控制:电商系统中防止超卖
- 账户余额操作:银行转账等金融操作
- 票务系统:座位预订等场景
高级特性
-
NOWAIT 选项:如果行已被锁定,立即返回错误而不等待
SELECT * FROM table_name WHERE condition FOR UPDATE NOWAIT; -
SKIP LOCKED 选项:跳过已被锁定的行
SELECT * FROM table_name WHERE condition FOR UPDATE SKIP LOCKED; -
等待超时:设置锁等待超时时间(MySQL 通过
innodb_lock_wait_timeout参数)
注意事项
- 必须在事务中使用(BEGIN/START TRANSACTION 和 COMMIT/ROLLBACK 之间)
- 过度使用可能导致性能问题和死锁
- 不同的数据库实现可能有细微差别(MySQL、PostgreSQL、Oracle等)
- 在没有合适索引的情况下可能导致表锁
示例
-- 银行转账场景
START TRANSACTION;
-- 锁定源账户
SELECT balance FROM accounts WHERE account_id = 123 FOR UPDATE;
-- 锁定目标账户
SELECT balance FROM accounts WHERE account_id = 456 FOR UPDATE;
-- 执行转账
UPDATE accounts SET balance = balance - 100 WHERE account_id = 123;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 456;
COMMIT;
SELECT ... FOR UPDATE 是处理并发数据修改的强大工具,但需要谨慎使用以避免性能问题。

2万+

被折叠的 条评论
为什么被折叠?



