redis官方文档地址:http://www.redis.cn/topics/distlock.html
redis命令参考手册:http://redisdoc.com/string/set.html
前言:
一般都是处理大数据量并发请求用到的redis锁机制,以下都是自己写的也有借鉴的网络。
实现原理:
- 互斥性
- 保证同一时间只有一个客户端可以拿到锁,也就是可以对共享资源进行操作
- 安全性
- 只有加锁的服务才能有解锁权限,也就是不能让a加的锁,bcd都可以解锁,如果都能解锁那分布式锁就没啥意义了
- 可能出现的情况就是a去查询发现持有锁,就在准备解锁,这时候忽然a持有的锁过期了,然后b去获得锁,因为a锁过期,b拿到锁,这时候a继续执行第二步进行解锁如果不加校验,就将b持有的锁就给删除了
- 避免死锁
- 出现死锁就会导致后续的任何服务都拿不到锁,不能再对共享资源进行任何操作了
redis为什么可以做分布式锁?
Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。
代码实现的,主要是针对某一笔数据的流水号加锁,防止多个线程写入这个数据。(具有互斥性)
配置文件:
redis.clients jedis 2.9.0 org.redisson redisson 3.10.5从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
EX seconds:将键的过期时间设置为seconds秒。执行SET key value EX seconds的效果等同于执行SETEX key seconds value。PX milliseconds:将键的过期时间设置为milliseconds毫秒。执行SET key value PX milliseconds的效果等同于执行PSETEX key milliseconds value。NX:只在键不存在时, 才对键进行设置操作。执行SET key value NX的效果等同于执行SETNX key value。XX:只在键已经存在时, 才对键进行设置操作。
具体实现只需要看:NX : 只在键不存在时, 才对键进行设置操作。
实现代码:
实现的原理其实很简单,就是通过查询redis缓存中是否有这个数据,没有了就查询数据库并且加个锁,其他的请求就进不来了,然后进入自旋状态,等第一个查询到数据添加到缓存中,其他的请求从自旋中出来再次发起请求,就在redis中拿到数据了。
@Overridepublic PmsSkuInfo getSkuById(String skuId) {
PmsSkuInfo pmsSkuInfo = new PmsSkuInfo(); // 链接缓存 Jedis jedis = redisUtil.getJedis(); // 查询缓存 String skuKey = "sku:" + skuId + ":info"; String skuJson = jedis.get(skuKey); if (StringUtils.isNotBlank(skuJson)) {//相当于if(skuJson!=null&&!skuJson.equals("")) pmsSkuInfo = JSON.parseObject(skuJson, PmsSkuInfo.class);//把json字符串转换成java类 } else {// 如果缓存中没有,查询mysql // 设置分布式锁 nx键不存在时操作 String OK = jedis.set("sku:" + skuId + ":lock", "1", "nx", "px", 10*1000); if (StringUtils.isNotBlank(OK) && OK.equals("OK")) {// 设置成功,有权在10秒的过期时间内访问数据库 pmsSkuInfo = getSkuByIdFromDb(skuId); if (pmsSkuInfo != null) {// mysql查询结果存入redis 1111111111111111111111111111111 jedis.set("sku:" + skuId + ":info", JSON.toJSONString(pmsSkuInfo)); } else {// 数据库中不存在该sku // 为了防止缓存穿透将,null或者空字符串值设置给redis jedis.setex("sku:" + skuId + ":info", 60 * 3, JSON.toJSONString("")); }//在访问MySQL后释放锁 jedis.del("sku: + skuId + :lock"); } else {// 设置失败,自旋(该线程在睡眠几秒后,重新尝试访问本方法) try {
Thread.sleep(3000); } catch (InterruptedException e) {
e.printStackTrace(); }return getSkuById(skuId); }
}
jedis.close(); return pmsSkuInfo;}大家有不懂得地方可以加QQ群1126420499一起互相交流。
序言:自己写的第一篇文章
觉得好的可以关注我一下,给我点动力。
















