跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 一个关于 mysql 锁问题
未分類
27 6 月 2020

一个关于 mysql 锁问题

一个关于 mysql 锁问题

資深大佬 : duanzs 2

背景:一个定时任务(多实例),取表 A 中状态为“初始化”的记录,然后取表 B 中对应记录,B 库存-A 消费存在两种情况。若 B-A=0,AB 记录都职位“完成”状态;若 B-A>0,AB 记录都职位“完成”状态后,再生成一条新的 B 记录,库存字段值=B-A ;

正常情况一:AB 各一条记录,库存与消费相等,AB 完成; 正常情况二:AB 各一条记录,库存大于消费,AB 完成,新生成一条库存记录 B ; 正常情况三:库存 B 一条记录,值为 8,消费 A1 、A2 两条记录,值都为 4 。首先 A1 与 B 进行操作,8-4=4>0,A1 和 B 完成,然后生成一条新 B,值为 4,然后 A2 和新 B 操作后全部完成。

异常情况:根据正常情况三,A1 与 A2 先后执行没问题,但是因为是多实例,A1 和 A2 可能同时执行,同时查询到 B 那一条记录,然后俩都 8-4=4>0,最后生成俩新 B 记录

理想结果:B 那条记录能不能加个锁或其它手段控制一下(表数据量大,肯定不能锁整个表),让 A1 和 A2 先后顺序执行,避免同时执行

注:业务比较复杂,并非只是库存-消费者一个小逻辑,此处简化问题了

大佬有話說 (9)

  • 資深大佬 : AngryPanda

    内存锁,lockName = B 表的 ID

  • 資深大佬 : AngryPanda

    乐观锁: UPDATE/INSERT XXX WHERE B.quantity = 8

  • 資深大佬 : AngryPanda

    悲观锁:select xxx for update

  • 資深大佬 : AngryPanda

    其实我觉得设计上稍微有点奇怪了:B > A 库存表为啥需要新生成记录呢?

  • 主 資深大佬 : duanzs

    @AngryPanda 这只是一个简化描述,其实业务上远比描述的复杂

  • 資深大佬 : peyppicp

    想顺序就 3 悲观锁,b 表里如果有唯一索引的话,select for update 行锁锁住,然后再做业务就行了,如果有并发也会在这行锁这里等待的。

  • 資深大佬 : PopRain

    update 库存表 set 库存=4 where PK=xx and 库存=8 肯定有一个 UPDATE 不成功的。。。。 (一般关键的更新,都要加上控制字段(或者说版本字段),例子中,原来的库存量就是“控制字段”,肯定要保证更新的是你原来的数据,这个都是开发 ERP 应用的常识。

    现在很多人都是根据主键去 UPDATE,当然有问题了(估计是某些 ORM 自身的限制,或者对 ORM 了解不深)

  • 資深大佬 : crclz

    你这个是没有任何问题的。因为,你会将旧的 B 置为“完成”,相当于给 B 上了一个 X 锁,所以是没问题的。

  • 資深大佬 : crclz

    同时,如果你的两个事务对 B 先读取的时候没有 FOR UPDATE,那么实际情况就会构成死锁,或者等待。当然,死锁是没有任何问题的,只不过会牺牲一个事务。整个流程是没有问题的,我只是解释一下内部运行过程。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具