欢迎光临中国护送网
详情描述

SELECT FOR UPDATE 是 MySQL 中用于行级锁的语句,主要作用是锁定查询到的行,防止其他事务修改这些行,确保数据的一致性。

基本语法

SELECT * FROM table_name WHERE condition FOR UPDATE;

使用场景

1. 悲观锁实现

在事务中先锁定数据,再进行更新操作:

START TRANSACTION;

-- 锁定符合条件的行
SELECT * FROM accounts WHERE user_id = 123 FOR UPDATE;

-- 执行更新操作(其他事务无法修改被锁定的行)
UPDATE accounts SET balance = balance - 100 WHERE user_id = 123;

COMMIT;

2. 防止库存超卖

START TRANSACTION;

-- 锁定库存记录
SELECT stock FROM products WHERE id = 1001 FOR UPDATE;

-- 检查库存并扣减
UPDATE products SET stock = stock - 1 WHERE id = 1001 AND stock > 0;

COMMIT;

重要特性

1. 事务中生效

FOR UPDATE 只在事务中有效:

-- 正确用法
START TRANSACTION;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 其他操作
COMMIT;

-- 错误用法(非事务中无效)
SELECT * FROM users WHERE id = 1 FOR UPDATE;

2. 锁等待超时

默认会一直等待锁释放,可以设置超时时间:

-- 设置锁等待超时为5秒
SET innodb_lock_wait_timeout = 5;

START TRANSACTION;
SELECT * FROM orders FOR UPDATE;

3. 锁定范围

  • 有索引时:锁定符合条件的行(行级锁)
  • 无索引时:可能升级为表锁
  • 主键查询:锁定指定的主键行

实际应用示例

示例1:转账操作

START TRANSACTION;

-- 锁定两个账户
SELECT * FROM accounts WHERE id IN (1, 2) FOR UPDATE;

-- 执行转账
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;

COMMIT;

示例2:订单处理

START TRANSACTION;

-- 锁定用户和商品
SELECT * FROM users WHERE id = 100 FOR UPDATE;
SELECT * FROM products WHERE id = 5 FOR UPDATE;

-- 创建订单
INSERT INTO orders (user_id, product_id, quantity) 
VALUES (100, 5, 1);

COMMIT;

与其他锁的比较

锁类型 语法 作用
排他锁 FOR UPDATE 阻止其他事务读写
共享锁 LOCK IN SHARE MODE 允许其他事务读,阻止写
乐观锁 版本号/时间戳 通过版本控制实现

注意事项

1. 性能影响

  • 锁定的行越多,性能影响越大
  • 可能导致死锁
  • 增加锁等待时间

2. 避免死锁

-- 按相同顺序锁定表,避免死锁
-- 事务1和事务2都按 id 升序锁定
SELECT * FROM accounts WHERE id IN (1, 2, 3) ORDER BY id FOR UPDATE;

3. 锁升级

当锁定的行过多时,InnoDB 可能将行锁升级为表锁。

4. 隔离级别影响

不同隔离级别下 FOR UPDATE 的行为:

隔离级别 FOR UPDATE 行为
READ COMMITTED 锁定实际存在的行
REPEATABLE READ 锁定实际存在的行和间隙

最佳实践

尽量缩小锁定范围

-- 不好:可能锁定多行
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;

-- 更好:精确锁定 SELECT * FROM orders WHERE id = 1001 FOR UPDATE;


2. **尽快释放锁**
```sql
START TRANSACTION;
-- 业务操作尽量放在锁外
SET @amount = 500;

-- 锁定后立即完成更新
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE;
UPDATE accounts SET balance = balance - @amount WHERE id = 1;

COMMIT;  -- 立即提交释放锁

使用超时机制

SET innodb_lock_wait_timeout = 3;  -- 3秒超时

考虑替代方案

  • 乐观锁(版本控制)
  • Redis 分布式锁
  • 消息队列削峰填谷

常见错误

-- 错误1:非事务中使用
SELECT * FROM users FOR UPDATE;  -- 自动提交,锁立即释放

-- 错误2:锁定过多行导致性能问题
SELECT * FROM large_table WHERE create_time > '2023-01-01' FOR UPDATE;

-- 错误3:没有WHERE条件(锁定全表)
SELECT * FROM users FOR UPDATE;  -- 非常危险!

SELECT FOR UPDATE 是处理并发数据更新的重要工具,但需要谨慎使用,避免过度锁定影响系统性能。

相关帖子
不同身高体型的人,在寻找适合自己的正确坐姿时需要注意什么?
不同身高体型的人,在寻找适合自己的正确坐姿时需要注意什么?
如何查询某段高速在往年免费期间的拥堵历史,以辅助行程决策?
如何查询某段高速在往年免费期间的拥堵历史,以辅助行程决策?
海口市企业建站#网站制作设计,服务可靠
海口市企业建站#网站制作设计,服务可靠
2026年乘坐高铁时哪些新奇的物品可能会被限制随身携带
2026年乘坐高铁时哪些新奇的物品可能会被限制随身携带
海口市苹果app开发@企业网站开发设计,优秀开发团队
海口市苹果app开发@企业网站开发设计,优秀开发团队
2026年申请保障性租赁住房的具体条件有哪些,哪些人群符合优先资格?
2026年申请保障性租赁住房的具体条件有哪些,哪些人群符合优先资格?
许昌市长途救护车出租护送病人转院-长途救护车租车护送病人转院
许昌市长途救护车出租护送病人转院-长途救护车租车护送病人转院
商家因备用金不足而建议顾客使用移动支付,这算拒收现金吗?
商家因备用金不足而建议顾客使用移动支付,这算拒收现金吗?
安阳市crm系统开发#java开源cms二次开发,企业解决方案
安阳市crm系统开发#java开源cms二次开发,企业解决方案
指甲上的月牙大小和数量变化,到底与我们的身体健康有没有关系?
指甲上的月牙大小和数量变化,到底与我们的身体健康有没有关系?
新一代ETC设备在2026年有哪些技术升级,能带来哪些使用体验改善?
新一代ETC设备在2026年有哪些技术升级,能带来哪些使用体验改善?
扬州市短视频推广@专业网站建设服务,网站制作
扬州市短视频推广@专业网站建设服务,网站制作
南阳市120救护车出租收费标准-病人护送救护车租赁,随时派车全国护送
南阳市120救护车出租收费标准-病人护送救护车租赁,随时派车全国护送
常州市小视频代运营#专业网站设计开发,高端网站开发设计
常州市小视频代运营#专业网站设计开发,高端网站开发设计
长治市长途救护车出租转运病人-租救护车护送病人转院
长治市长途救护车出租转运病人-租救护车护送病人转院
株洲市安卓app开发@网站建设服务公司,网站制作
株洲市安卓app开发@网站建设服务公司,网站制作
2026年,哪些个人收入变化会直接触发公积金缴费基数的重新核定?
2026年,哪些个人收入变化会直接触发公积金缴费基数的重新核定?
晋中市病人转运服务电话-重症病人转院租救护车,车内设备齐全
晋中市病人转运服务电话-重症病人转院租救护车,车内设备齐全
新乡市救护车跨省护送病人回家-救护车转院病人返乡,收费合理
新乡市救护车跨省护送病人回家-救护车转院病人返乡,收费合理