【三大锁】悲观锁——mysql悲观锁

一 三大常用锁

  • 悲观锁
    •   你准备去银行取10w了,跟银行提前打个招呼,有个10w现金谁都别动。(一般只限制写-别人不能取那10w但是能查到银行总体余额,某些场景会限制读)
  • 乐观锁
    •   你准备取10w了,不打招呼,撸起袖子(开始事物,准备好回滚),直接去银行,到了之后,银行告诉你10w在那里,你正好取走(事物提交)。 也有可能去了后,银行说10w没了,那你不取了(事物回滚)
    •       这里面涉及到一个细节,你拿的10w可能是 路人甲 早上取走了最后10w,然后在你到达之前 路人乙 存了10w。 如果你的业务场景是必须要银行的新钱,而不是别人刚存的,那你可以问下银行这个钱是否有人动过(标记操作流水版本号,cas算法的特点)
  • 分布式锁
    •   饭店门口很多顾客(多个访问线程),但是餐桌资源只有空闲的时候才会让人进去。有客户取消或者用餐完毕,某个4人桌就空闲出来了,你就可以去抢占这个4人桌的号(分布式锁),先来先得!(和排号系统还是有点不一样的)

二 实现方式

  • 分布式锁
    •   基本都是拿悲观锁(如 redis: setnx+看门狗+unique_value)
  • 乐观锁
    •   redis的watch
    •       mysql的step1: select step2: update .set. where id = pre_id and version = pre_version 然后判断result是否>0
    •       cas算法基本原理类似,需考虑version
  • 悲观锁
    • reids的setnx + 看门狗
    • 不限制消息发送频率只限制重复发送的场景,可以带上msgid作为setnx的value
    • 怕del错lock,可以把uniq_id 作为setnx的value,然后del之前,get判断uniq_id是否一致! get和del可以通过lua制作成原子命令!
    • mysql的select for update (本文重点)

 

三 mysql悲观锁

用户x下单,系统查询是否有存货,生成订单balabala ( 我们称为process ),存货-1
process的过程中,可能用户y 就下单了,或者比你下单早的用户z 刚好结算到存货-1了,那用户x 直接把库存降到-1了。 虽然可能有数据库unsigned等保护,那如果库存设置的是底货必须是10以上呢?

 所以我们要用到select ..  for update

这玩意就是把select 直接锁住,不让别人增删改(查允许)

如果命中了索引,含主键索引、唯一索引,那么是行锁;否则是表锁;

 cmd1 不commit

 

 

cmd2 会阻塞

 


然后cmd1 commit;则cmd2 success

 

 如果cmd2要update等操作,会命中cmd1的查询结果行(只要包含cmd1的结果,你想想,别人锁住了,你却要动他,虽然你要动1w行,只有其中一行是cmd1的结果,但是就是卡住了,没办法!), 则会阻塞,时间久了会down;未命中cmd1的查询结果行,则没有任何影响。 

cmd1如果resulet为空,那么根据上条结论,也能知道,相当于没锁。

 

 

 

因为name是非索引,这时候直接锁表了,虽然和cmd1的result无关,还是卡住了! 

 

posted @ 2022-08-19 17:35  布叔喂丶  阅读(67)  评论(0编辑  收藏  举报