举例说明 MySQL 乐观锁和悲观锁的使用场景。

考查重点:冲突频率与等待、重试代价。低冲突文档version条件更新是乐观,余额等短事务先FOR UPDATE再改是悲观,按重试/等待代价选

本题目录

参考答案

核心回答

MySQL 中,乐观锁适合冲突较少、允许检测冲突后重试或提示用户的更新,常用版本号或业务状态作为更新条件;悲观锁适合一段短事务里需要先读后改、并保护多步判断的场景,通常使用 InnoDB 的锁定读,让竞争者等待。

例如,后台编辑商品信息时,可在保存时检查读取的版本号,版本变化就提示冲突,避免覆盖别人修改。账户内部转账若需要读取两条余额、校验并更新,可以在同一事务中按固定顺序锁定账户,完成后提交。这里是策略示例,具体选择还取决于冲突率、事务长度和失败处理成本。

乐观锁怎样保护一次修改

假设两个人都读取商品版本 7。第一个请求以“版本仍为 7”为条件更新内容,并把版本改为 8;第二个请求再按版本 7 更新时匹配不到记录,就应把它识别为冲突,重新读取并决定合并、重试或返回冲突提示。

版本检查和更新必须是同一条原子数据库操作,先查版本再无条件写回仍会丢失更新。还要检查受影响行数,避免把未匹配、记录不存在或业务条件失败一律当作成功。数据库执行这类更新仍可能获取行锁,所以“乐观锁”不等于底层完全没有锁。

低冲突时,它减少了从读取到提交之间的长期占锁;冲突频繁时,大量重读与重算会浪费资源。重试还需要上限,不能遇到冲突就无限循环。

悲观锁怎样保护多步判断

在显式事务中读取需要修改的记录并加锁,校验约束、执行修改,再提交或回滚。竞争事务请求不兼容的锁时需要等待,或按配置快速返回失败。

账户转账应按账户 ID 等稳定顺序获取两边的锁,减少相反顺序带来的死锁;事务里不要夹带用户输入等待和慢速外部调用。查询要命中适当索引,实际锁范围还受索引、查询条件和隔离级别影响,锁范围应结合索引与实际扫描范围判断,而不能只看 SQL 的表面条件。

进一步追问

  • 扣库存必须先查再加锁吗? 不一定。如果一个带库存条件的原子更新已能表达约束,就可以直接完成检查与扣减;需要同时维护订单、流水等状态时再组织事务。
  • 加锁能保证幂等吗? 加锁只控制并发。锁释放后重复请求仍能再次到达,还需业务唯一键或状态机识别同一笔操作。
  • 发生死锁怎么办? 先回滚并识别可重试事务,有限重试;同时查看死锁记录,检查加锁顺序、索引扫描范围和长事务。不要把数据库主动回滚当作业务已提交。

参考资料

相关面经

3 篇

哔哩哔哩(B站)

后端开发工程师(游戏广告)
实习
查看原面经 →
乐观锁与悲观锁

小红书、百度

面经合集实习
查看原面经 →
你能举例平时用到的 MySQL 乐观锁、悲观锁的场景吗?

字节跳动

AI 应用开发工程师
日常实习一面
查看原面经 →
追问
实际开发中有没有使用过乐观锁和悲观锁?

相关题目

4 题