分布式锁
分布式锁的使用场景是什么呢?
之前红包需求的时候,有一个场景要用到分布式锁。同一个openid,最多只能抢到一个子红包。
1、先判断这个openid在不在该红包对应的已抢openid hash中
String hget(String key, String field);
2、如果在,就返回。如果不在,则加分布式锁,保证同一个openid,最多只有一个请求能抢到红包。这里是怕有人用自己的openid刷接口,从而导致他自己抢了很多个红包。
SET key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
只有这个命令,能一边设不存在时才set,一边设置过期时间。
SETNX key value,只能在不存在时才set,不能设置过期时间。
key是什么?key是openid+redPacketId。
value是什么?value是一个uuid即可,后面还要依靠这个uuid去解锁呢。对的,分布式锁加上之后,需要我们在业务完成之后,手动解锁。即del key,但是不能乱删,不能是没有获取到锁的客户端把锁解了,只能是获取到锁的客户端才能解锁。这就是uuid的好处,每个请求生成的uuid是不一样的,只有uuid是key的值时,才能解锁。
伪代码如下:
public Object getChildRedPacket() { JedisCommands jedisCommands = null; Jedis jedis = null; JedisCluster jedisCluster = null; String openid = "d"; String redPacketId = "ss"; String lockKey = openid + redPacketId; SetParams setParams = new SetParams(); setParams.nx(); setParams.ex(60 * 60); String uuid = UUID.randomUUID().toString(); String money = jedisCommands.hget(redPacketId, openid); if (StringUtils.isNotBlank(money)) { return ImmutableMap.of("money", money); } else { try { // 获得锁 if ("ok".equalsIgnoreCase(jedisCommands.set(lockKey, uuid, setParams))) { money = jedisCommands.lpop(redPacketId); if (StringUtils.isNotBlank(money)) { jedisCommands.hset(redPacketId, openid, money); return ImmutableMap.of("money", money); } else { return ImmutableMap.of("msg", "已抢完"); } } } finally { // 释放锁 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return end"; // jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uuid)); jedisCluster.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uuid)); } } return null; }
Jedis常规的set、get、hset、hget方法都是从JedisCommands接口继承的,JedisCluster常规的set、get、hset、hget方法都是从JedisClusterCommands接口继承的。
Jedis的eval方法是从ScriptingCommands接口继承的,JedisCluster的eval方法是从JedisClusterScriptingCommands接口继承的。
注意以上代码,在lua脚本中用了uuid的值,这就是约束了只有获得锁的请求能解锁,没有获得锁的请求不能解锁,且释放锁代码放在finally块中。
加锁时的过期时间怎么定呢?只要是比业务代码执行所需时间长就好了,长点无所谓。为啥无所谓呢?因为锁是一个openid对应一个redPacketId,锁不释放不会影响另一个openid抢这个红包,也不会影响这个openid抢另一个红包,只会影响这个openid再一次抢这个红包。参考https://mp.weixin.qq.com/s/ceRwZdwOgmzRGqF9HZztKg
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】