MySQL悲观锁需在事务中用SELECT...FOR UPDATE或LOCK IN SHARE MODE显式加锁,配合REPEATABLE READ隔离级;锁随事务结束释放,须避免无索引查询、锁范围过大及死锁。
在 MySQL 中实现悲观锁控制并发更新,核心是借助数据库的行级锁机制,在事务中显式加锁,确保同一时间只有一个事务能修改某条记录。关键在于合理使用 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE,并配合事务隔离级别(推荐 REPEATABLE READ)和正确提交/回滚逻辑。
悲观锁不是自动生效的,必须在事务内主动发起带锁查询:
于“读取后要更新”的典型场景,如扣减库存、转账。它会锁定查到的行(含间隙),阻止其他事务对该行做 UPDATE、DELETE 或再次 FOR UPDATE。FOR UPDATE 在 REPEATABLE READ 下默认使用 next-key lock(行锁 + 间隙锁),能防止幻读;若只查主键且值存在,则退化为行锁。锁只在事务内有效,事务结束(COMMIT 或 ROLLBACK)时自动释放:
BEGIN 或 START TRANSACTION),避免语句自动提交导致锁瞬间释放。UPDATE 必须在同一个事务中,否则锁已失效。很多并发问题源于对锁行为理解偏差:
FOR UPDATE 的 WHERE 条件未命中索引,MySQL 可能升级为表级锁,极大降低并发能力。务必确认执行计划(EXPLAIN)显示走了索引。SELECT * FROM t WHERE id > 100 FOR UPDATE 会锁住所有满足条件的行及之间的间隙,可能影响无关记录的插入。Deadlock found),应用层需捕获并重试。假设商品表 products(id, stock),扣减 ID=123 的库存 1 件:
START TRANSACTION; SELECT stock FROM products WHERE id = 123 FOR UPDATE; -- 应用层判断 stock >= 1 UPDATE products SET stock = stock - 1 WHERE id = 123; COMMIT;
若库存不足,应在事务内直接 ROLLBACK 并返回错误,避免无效更新。