setnx,是set if not exists的缩写,也就是只有不存在的时候才设置,设置成功时返回1,设置失败时返回0。可以利用它来实现锁的效果,但是很多人在使用的过程中都有一些问题没有考虑到。

例如某个查询数据库的接口因为请求量比较大所以加了缓存,并设定缓存过期后刷新。当并发量比较大并且缓存过期的瞬间,大量并发请求会直接查询数据库导致雪崩。如果使用锁机制来控制只有一个请求去更新缓存就能避免雪崩的问题。下面是很多人下意识想到的加锁方法

$rs = $redis->setnx($key, $value);
if ($rs) {//处理更新缓存逻辑$cache->update();//删除锁$redis->del($key);
}

通过setnx获取锁,如果成功了则更新缓存然后删除锁。其实这里有一个严重的问题:如果更新缓存的时候因为某些原因意外退出了,那么这个锁就不会被删除而一直存在,以至于缓存再也得不到更新。为了解决这个问题有人可能会想到给锁设置一个过期时间,如下

$redis->multi();
$redis->setnx($key, $value);
$redis->expire($key, $ttl);
$redis->exec();

因为setNX不具备设置过期时间的功能,所以要借助Expire来设置,同时需要使用Multi/Exec来确保请求的原子性,以免setnx成功了Expire却失败了。这样还有问题:当多个请求到达时,虽然只有一个请求的setnx可以成功,但是任何一个请求的Expire却都可以成功,这就意味着即便获取不到锁也可以刷新过期时间,导致锁一直有效,还是解决不了上面的问题。显然setnx满足不了需求,Redis从2.6.12起,set涵盖了setnx的功能,set本身又包含了设置过期时间的功能,所以使用set就可以解决上面遇到的问题。

$rs = $redis->set($key, $value, array('nx', 'ex' => $ttl));
if ($rs) {//处理更新缓存逻辑// ......//删除锁$redis->del($key);
}

到这一步其实还是有问题的,如果一个请求更新缓存的时间比锁的有效期还要长,导致在缓存更新过程中锁就失效了,此时另一个请求就会获取到锁,但前一个请求在缓存更新完毕的时候,直接删除锁的话就会出现误删其它请求创建的锁的情况。所以要避免这种问题,可以在创建锁的时候需要引入一个随机值并在删除锁的时候加以判断。

$rs = $redis->set($key, $random, array('nx', 'ex' => $ttl));
if ($rs) {//处理更新缓存逻辑// ......//先判断随机数,是同一个则删除锁if ($redis->get($key) == $random) {$redis->del($key);}
}

正确使用Redis的setnx实现锁机制相关推荐

  1. nx set 怎么实现的原子性_正确地使用Redis的SETNX实现锁机制

    setNX,是set if not exists 的缩写,也就是只有不存在的时候才设置, 设置成功时返回 1 , 设置失败时返回 0 .可以利用它来实现锁的效果,但是很多人在使用的过程中都有一些问题没 ...

  2. Redis的事务和锁机制(乐观锁和悲观锁)

    Redis学习笔记(四) 1,Redis事务的定义 2,Redis事务操作的三个基本命令 3,解决Redis中的事务冲突(乐观锁和悲观锁) 3.1,悲观锁 3.2,乐观锁 3.3,Redis中使用乐观 ...

  3. 【Redis】事物和锁机制乐观锁悲观锁

    目录 1. Redis 的事务定义 2. Multi.Exec.discard 3. 事务的错误处理 4. 事务冲突的问题 悲观锁 乐观锁 1. Redis 的事务定义 Redis 事务是一个单独的隔 ...

  4. Java 并发编程解析 | 如何正确理解Java领域中的锁机制,我们一般需要掌握哪些理论知识?

    苍穹之边,浩瀚之挚,眰恦之美: 悟心悟性,善始善终,惟善惟道! -- 朝槿<朝槿兮年说> 写在开头 提起Java领域中的锁,是否有种"道不尽红尘奢恋,诉不完人间恩怨"的 ...

  5. 【Redis】事务和锁机制

    一.事务的基本操作 1.redis中事务的概念不同于Mysql数据库中的事务 它是一个单独的隔离操作:事务中所有的命令都会序列化.按照顺序依次执行 事务在执行的过程中,不会被其他客户端发送的命令请求打 ...

  6. Redis实现分布式锁机制的原理

    Redis中实现分布式锁机制 加锁 使用setnx(商品ID,1): 返回0,代表redis里面有数据,即数据已经加锁: 返回1,代表redis里面没有数据,即可以获得锁. 解锁 使用redis的de ...

  7. redis setnx 分布式锁_Spring Boot 整合 Redis 正确的实现分布式锁

    前言 最近在做分块上传的业务,使用到了Redis来维护上传过程中的分块编号. 每上传完成一个分块就获取一下文件的分块集合,加入新上传的编号,手动接口测试下是没有问题的,前端通过并发上传调用就出现问题了 ...

  8. 秒杀设计--mysql的锁机制应用和redis方案

    2019独角兽企业重金招聘Python工程师标准>>> 背景 在工作中接到一个需求:对于访问页面的前x名用户分发A奖品,x+1名及以后的用户分发另外一种奖品.在J2EE的开发中,我们 ...

  9. Redis 学习笔记-NoSQL数据库 常用五大数据类型 Redis配置文件介绍 Redis的发布和订阅 Redis_事务_锁机制_秒杀 Redis应用问题解决 分布式锁

    1.NoSQL数据库 1.1 NoSQL数据库概述 NoSQL(NosQL = Not Only sQL ),意即"不仅仅是sQL",泛指非关系型的数据库.NoSQL不依赖业务逻辑 ...

最新文章

  1. Java 详解 JVM 工作原理和流程
  2. IIS 7.5 配置伪静态方法
  3. webpack打包发布
  4. Typescript学习;Typescript总结;Typescript 的数据类型有哪些?
  5. OpenCV-计算二维矢量幅值cv::magnitude
  6. 提高数据质量的方法有哪些
  7. 可以检测手机帧率和温度的软件_手机帧数测试教学,含免费软件下载,使用方法,数据分析方法详解...
  8. 算法图解第四章笔记与习题(快速排序)
  9. mysql命令执行cmd命令_mysql cmd常用命令
  10. 如何排查内存飙升的情况
  11. 让Fireball CodeEditor控件禁止中文双倍输入
  12. SpringBoot之如何自定义一个starter模块
  13. Tensorflow学习-自定义模型
  14. python能制作ppt动画效果吗_我可以用Python制作动画吗?
  15. 厦门大学研究生计算机复试分数线,关于2018厦门大学研究生考试复试分数线的一些公告...
  16. 品优购项目--注册页面
  17. 微信个人号客服系统淘宝客发单机器人sdk服务端接口列表
  18. poi实现单元格行合并
  19. VB版机房收费系统流程图--00
  20. java 完全匹配_正则表达式的完全匹配和部分匹配

热门文章

  1. AD 域控同步相关命令
  2. 美化Ubuntu桌面——苹果
  3. ring3层一种占用文件的方法(DuplicateHandle以后,把占用文件的句柄丢给系统进程,导致被占用)
  4. 科大讯飞CTR预估挑战赛Top3方案总结
  5. Github 切换分支
  6. python如何画动态海浪_python 事务
  7. Nginx 配置数据库服务代理
  8. Linux 常用命令、英文全称、中文翻译
  9. Python的codecs模块
  10. python+selenium爬虫按照名单循环爬取作者知网下载量等信息