MySQL数据库中FOR UPDATE的使用
在MySQL中,FOR UPDATE是一个非常重要的锁机制,主要用于在事务中锁定查询到的数据行,防止其他事务修改这些数据。 基本语法 sql 复制代码 SELECT * FROM table_name WHERE condition FOR UPDATE; 主要作用 1. 行级排他锁 对查询结果集加排他锁(X锁) 其他事务无法对这些行加任何锁,包括读锁和写锁 其他事务可以普通读取(取决于隔离级别),但不能修改 2. 防止数据竞争 在并发环境下,防止多个事务同时修改同一数据: sql 复制代码 -- 事务1 START TRANSACTION; SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; -- 此时其他事务无法修改id=1的记录 UPDATE accounts SET balance = balance - 100 WHERE id = 1; COMMIT; 使用场景 1. 库存扣减 sql 复制代码 START TRANSACTION; SELECT stock FROM products WHERE id = 1001 FOR UPDATE; -- 检查库存并扣减 UPDATE products SET stock = stock - 1 WHERE id = 1001; COMMIT; 2. 账户余额操作 sql 复制代码 START TRANSACTION; SELECT balance FROM accounts WHERE user_id = 123 FOR UPDATE; -- 确保余额充足后进行转账 UPDATE accounts SET balance = balance - 500 WHERE user_id = 123; COMMIT; 3. 订单处理 sql 复制代码 START TRANSACTION; SELECT * FROM orders WHERE status = 'pending' FOR UPDATE; -- 处理待处理订单 UPDATE orders SET status = 'processing' WHERE status = 'pending'; COMMIT; 注意事项 1. 必须在事务中使用 sql 复制代码 -- 错误用法(不在事务中) SELECT * FROM table FOR UPDATE; -- 正确用法 START TRANSACTION; SELECT * FROM table FOR UPDATE; -- ... 其他操作 COMMIT; 2. 锁的释放 锁在事务提交或回滚时自动释放 长时间持有锁会影响并发性能 3. 索引的重要性 sql 复制代码 -- 使用主键索引(高效) SELECT * FROM users WHERE id = 1 FOR UPDATE; -- 无索引字段可能导致表锁(性能差) SELECT * FROM users WHERE name = 'John' FOR UPDATE; 4. 与其他锁的区别 锁类型 说明 其他事务能否读取 其他事务能否修改 FOR UPDATE 排他锁 可以(READ COMMITTED) 不可以 LOCK IN SHARE MODE 共享锁 可以 不可以 实际示例 sql 复制代码 -- 银行转账场景 START TRANSACTION; -- 锁定转出账户 SELECT balance FROM accounts WHERE account_no = 'A001' FOR UPDATE; -- 锁定转入账户 SELECT balance FROM accounts WHERE account_no = 'B002' FOR UPDATE; -- 执行转账操作 UPDATE accounts SET balance = balance - 1000 WHERE account_no = 'A001'; UPDATE accounts SET balance = balance + 1000 WHERE account_no = 'B002'; COMMIT; 性能建议 尽量缩短锁持有时间 确保查询条件使用索引 避免在高峰期对热点数据使用 考虑使用乐观锁替代 FOR UPDATE是保证数据一致性的重要工具,但需要谨慎使用以避免死锁和性能问题。