news 2026/6/15 20:05:33

数据库的乐观锁和悲观锁的区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据库的乐观锁和悲观锁的区别

1. 悲观锁 (Pessimistic Lock) —— “占着茅坑不拉屎”

核心心态:悲观。我觉得总有人想害朕(想抢我的数据)。
做法:只要我开始用这条数据,我就把门锁死。在我处理完之前,谁也别想碰,连“读”都不行,都在外面排队!

生活比喻:上公厕
  1. 你进了一个单间。
  2. 咔嚓,把门插销锁上(数据库行锁)。
  3. 你在里面玩手机、看报纸(处理业务逻辑)。
  4. 外面来了 100 个人,推门发现打不开,只能在门口干等着(阻塞 Blocked)。
  5. 你完事了,开门出来(提交事务 Commit)。
  6. 下一个人才能进去。
SQL 是怎么写的?

你需要显式地告诉数据库“给我锁上”:

-- 开启事务BEGIN;-- 重点是 FOR UPDATE,这句话一出,这行数据就被你独占了SELECTstockFROMgoodsWHEREid=1FORUPDATE;-- 在这期间,别的线程执行 SELECT ... FOR UPDATE 会被卡死在这里UPDATEgoodsSETstock=stock-1WHEREid=1;COMMIT;-- 只有等你提交了,锁才释放
  • 优点:绝对安全,数据绝对一致。
  • 缺点:性能极差。万一你在里面死锁了或者处理太慢,整个系统就瘫痪了。
  • 适用场景:数据极其敏感,且并发量很低(比如银行转账)。

2. 乐观锁 (Optimistic Lock) —— “Git 代码冲突”

核心心态:乐观。我觉得大部分时间没人跟我抢。
做法:我不锁门,大家随便进,随便读。但是我提交修改的时候,我要检查一下,在我修改期间,有没有别人偷着改过数据。

生活比喻:Git 提交代码
  1. Pull:你和小王都把index.vue拉到了本地(Version 1)。
  2. Edit:你在本地改代码,小王也在本地改代码。互不影响。
  3. Push(关键时刻):
    • 小王手快,先提交了(Version 变成 2)。
    • 你后提交,Git 告诉你:“冲突了!你的版本(V1)过期了,现在的最新版是 V2。”
  4. Retry:你只能重新拉取最新代码,合并一下,再提交。
数据库怎么实现?(重点:版本号机制)

通常我们在表里加一个字段:version(版本号)。

  1. 第一步:查数据
    • 线程 A 查到:stock = 1, version = 1
    • 线程 B 查到:stock = 1, version = 1
  2. 第二步:线程 A 抢先修改
    -- 我要把 version 变成 2,前提是现在的 version 必须还是 1UPDATEgoodsSETstock=0,version=2WHEREid=1ANDversion=1;
    • 结果:成功!数据库里的version变成了 2。
  3. 第三步:线程 B 慢了一拍去修改
    -- B 手里拿的 version 还是 1,它想把 version 变成 2UPDATEgoodsSETstock=0,version=2WHEREid=1ANDversion=1;-- 👈 此时数据库里的 version 已经是 2 了!
    • 结果:查找条件version = 1匹配不到任何行。更新失败(影响行数 0)。
    • 应用层反应:给用户报错“手慢了”,或者自动重试。
  • 优点:吞吐量极高,不用排队,大家都在跑。
  • 缺点:如果冲突太频繁(比如 100 个人抢 1 个),会有 99 个人失败,需要应用层处理重试逻辑。
  • 适用场景:互联网大部分场景(秒杀、点赞、评论)。

3. 在 Java (MyBatis-Plus) 里怎么用?

记得我之前推荐你的MyBatis-Plus吗?它把乐观锁封装成了“傻瓜式”操作。

第一步:数据库表里加个字段version,默认值 1。

第二步:Java 实体类加个注解。

publicclassGoods{privateLongid;privateIntegerstock;@Version// 👈 就加这一个注解,告诉 MP 这是乐观锁字段privateIntegerversion;}

第三步:配置一下插件(现在的代码里只需要注册一个 Bean)。

第四步:正常写代码。

// 1. 先查出来 (必须先查,拿到当前的 version)Goodsgoods=goodsMapper.selectById(1);// 假设此时 version=1// 2. 修改数据goods.setStock(goods.getStock()-1);// 3. 更新// MyBatis-Plus 会自动把你生成的 SQL 变成:// UPDATE goods SET stock=0, version=2 WHERE id=1 AND version=1intresult=goodsMapper.updateById(goods);if(result==0){return"抢购失败,被人截胡了!";// 没抢到锁}

总结

  • 悲观锁:FOR UPDATE。先锁后干。像红绿灯,红灯停绿灯行。
  • 乐观锁:version字段。先干后查。像斑马线,看着没人才走,走到一半发现有车来了就退回来。

在面试里,只要你能说出**“为了性能,我们一般优先使用基于版本号的乐观锁,除非是像金额扣减这种极度敏感的业务才考虑悲观锁”**

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 18:46:22

Linux下安装TensorFlow-GPU及CUDA配置指南

Linux下安装TensorFlow-GPU及CUDA配置指南 在深度学习项目中,GPU加速几乎成了标配。然而,当面对NVIDIA驱动、CUDA、cuDNN和TensorFlow之间错综复杂的版本依赖时,即便是有经验的开发者也常常被“劝退”。尤其是从零开始搭建一个稳定可用的Lin…

作者头像 李华
网站建设 2026/6/15 18:00:59

基于STM32单片机图像识别计数器颜色识别数量统计蓝牙无线APP/WiFi无线APP/摄像头视频监控/云平台设计S107

STM32-S107-图像识别颜色分类数量统计手动自动阈值TFT彩屏声光提醒按键(无线方式选择)产品功能描述:本系统由STM32F103C8T6单片机核心板、OLED屏、(无线蓝牙/无线WIFI/无线视频监控/联网云平台模块-可选)、摄像头模块、舵机模块、蜂鸣器报警、…

作者头像 李华
网站建设 2026/6/15 10:05:08

blender/ue为朋友生日礼物记录(可能是大一上结算。?)

是gift102好耶… 本来是在自己摸索与学习,然后前两天反应过来马上有朋友过生日,于是放下手里还在捏的oc想弄一个小小游戏送给朋友, 分为blender部分记录和ue部分记录 因为还在课上坐牢所以暂时发不了博客先写知乎,感觉自己有点…

作者头像 李华
网站建设 2026/6/14 17:42:36

基于STM32单片机太阳能路灯台灯锂电池电压电量PWM调光蓝牙无线APP/WiFi无线APP/摄像头视频监控/云平台设计S352

STM32-S352-太阳能USB灯光照锂电池电压电量充电电压自动手动升压声光提醒OLED屏阈值按键(无线方式选择)产品功能描述:本系统由STM32F103C8T6单片机核心板、OLED屏、(无线蓝牙/无线WIFI/无线视频监控/联网云平台模块-可选)、太阳能电池板、锂电…

作者头像 李华
网站建设 2026/6/15 13:56:30

万物皆可集成系列:低代码如何不成为数据孤岛

在技术领域,我们常常被那些闪耀的、可见的成果所吸引。今天,这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力,让我们得以一窥未来的轮廓。然而,作为在企业一线构建、部署和维护复杂系统的实践者,我们深知…

作者头像 李华
网站建设 2026/6/14 21:24:05

从零基础到入门实战:我的2025鸿蒙领航者养成记

目录 一、引言:偶然结缘,开启鸿蒙学习之路 二、入门摸索期:踩过的坑与关键突破 三、实战进阶期:第一个鸿蒙小应用诞生 四、社区融入期:从“索取”到“分享”的转变 五、总结:2025成长复盘与未来计划 一…

作者头像 李华