用Redis搞定多把锁其实没那么难,教你快速上手设置技巧
- 问答
- 2025-12-29 12:18:50
- 3
(引用来源:博客园、开发者个人技术博客、Redis官方文档应用实践章节)
很多人一听到要在系统里用Redis实现多把锁,就是同时锁住好几个资源,就觉得头大,感觉特别复杂,其实啊,你想错了,只要你理解了最核心的那个套路,就会发现用Redis搞定多把锁,真的没那么难,我今天就跟你聊聊这个,保证你快速上手。
你先别去想那些高深的术语,什么分布式事务、两阶段提交,那都太远了,咱们就从最实际的问题出发,想象一个场景:你要做一个电商系统里的订单支付功能,用户下单后,要同时锁住两样东西:第一,是用户的账户余额,防止他同时支付两笔订单导致超额扣款;第二,是商品的库存,防止超卖,你看,这不就是典型的需要两把锁的情况吗?
那最直接的想法是啥?就是按顺序,一把一把地锁呗,这个方法在大多数情况下就够用了,而且简单不容易出错,具体怎么做呢?

第一步,想好一个锁定的顺序。 这是最关键的一步,能避免死锁,什么是死锁?就是线程A锁了资源1,想去锁资源2,同时线程B锁了资源2,又想去锁资源1,结果俩人互相等着,谁也进行不下去,解决的办法就是大家都遵守同一个顺序,我们规定,无论什么业务操作,都按照“先锁用户ID,再锁商品ID”的顺序来加锁,哪怕有另一个操作是需要“先锁商品ID,再锁店铺ID”,我们也强行把它改成先锁用户ID(如果业务关联的话)或者按照字母表顺序、数字大小顺序,定个死规矩。
第二步,开始一把一把地加锁。 用Redis加锁,最常用的就是SET命令加上NX和PX参数。NX意思是只有这个key不存在的时候才设置成功,也就是抢锁;PX是给这个锁设置一个过期时间,比如10秒,这样就算程序出问题锁没释放,10秒后也会自动解开,防止系统死掉。
用户ID是123,商品ID是456,我们按照定好的顺序,先锁用户:
SET lock:user:123 “随机值” NX PX 10000
这个命令的意思是,去设置一个叫lock:user:123的键,如果这个键不存在(NX),就设置成功,并且给它10秒(10000毫秒)的存活时间,这个“随机值”很重要,最好是生成一个全局唯一的字符串,比如UUID,用来标识当前请求的客户端,这是为了安全,防止你误删了别人加的锁。

如果这个命令返回成功,好,用户锁拿到了,接下来锁商品:
SET lock:sku:456 “另一个随机值” NX PX 10000
如果这个也返回成功,恭喜你,两把锁都到手了!现在你就可以安心地执行核心业务逻辑了:检查余额、扣款、减库存。
第三步,处理加锁失败的情况。 现实不会总是一帆风顺,假如你在锁商品的时候失败了,说明这个商品已经被别的请求锁住了,那这时候你该怎么办?你之前已经成功锁住了用户啊!你必须把已经拿到手的用户锁给释放掉,然后等一小会儿(比如随机睡眠几百毫秒),再整个重试第一步。
这一步叫“锁申请失败时的回滚”,你不能因为第二把锁没拿到,就傻等着,那样你占着用户锁,别的需要锁这个用户的请求也进不来,可能引起连锁反应,要么全拿到,要么就都释放掉重来,这个重试的逻辑一般要有个次数限制,比如重试3次还不行,就告诉用户“系统繁忙”。

第四步,释放锁。 等你业务逻辑都做完了,就要释放锁了,释放锁也不能简单地用DEL命令删除key,因为可能因为你业务执行时间太长,锁已经过期自动释放了,然后又被别的请求获取了,如果你这时候直接删除,就把别人的锁给删了,会出大乱子。
所以正确的姿势是,用Lua脚本,Lua脚本能保证原子性执行,脚本的逻辑是:先检查lock:user:123对应的值,是不是你当初设置的那个“随机值”,如果是,说明这个锁还是你持有的,那你就可以删除它;如果不是,说明锁已经不属于你了,你就不能删。
先释放商品锁,再释放用户锁,释放顺序和加锁顺序相反,这是一种好习惯。
你看,整个过程就像我们现实生活中一样:你想用会议室A和会议室B开会,你得先按照规矩(比如先申请编号小的A)拿到A的钥匙,然后再去拿B的钥匙,如果B的钥匙被人拿走了,你也不能一直等着,你得先把A的钥匙还回去,告诉别人A现在可用了,然后过会儿再来同时申请两把钥匙。
上面说的这是最基础、最实用的方法,如果你的业务非常复杂,需要同时锁几十个资源,或者对性能要求极高,那可能需要更高级的方案,比如把这些需要锁的资源合并成一个key,或者使用RedLock算法,但对于90%的日常场景,这个“按顺序逐把加锁,失败则释放已得锁并重试”的策略,已经完全够用且非常可靠了。
你找个测试环境,按照这个步骤写代码实现一遍,基本上就能掌握精髓了,核心就是那四个步骤:定顺序、逐加锁、失败回滚、安全释放,多试几次,你就能快速上手了。
本文由酒紫萱于2025-12-29发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/70644.html
