redis加锁的几种方式汇总

 更新时间:2023年03月07日 14:18:09   作者:SeaDhdhdhdhdh  
这篇文章主要介绍了redis加锁的几种方式汇总,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

redis常见的加锁命令分别是INCR、SETNX、SET

1、INCR

这种锁的加锁思路是:

key不存在,那么key的值会先被初始化为0,然后再执行INCR操作进行加一。

然后其它用户在执行INCR操作进行加一时,如果返回的数值大于1,说明这个key正在被锁定使用。

1、 客户端A请求服务器获取key的值为1表示获取了锁    

2、 客户端B也去请求服务器获取key的值为2表示获取锁失败    

3、 客户端A执行代码完成,删除锁    

4、 客户端B在等待一段时间后在去请求的时候获取key的值为1表示获取锁成功    

5、 客户端B执行代码完成,删除锁 

$redis->incr($key);
$redis->expire($key, $ttl); //设置生成时间为1秒 

具体使用命令:

127.0.0.1:6379>INCR keyName

2、SETNX

这种加锁的思路是,如果key不存在,将key设置为value,如果key存在,则SETNX不做任何动作。

SETNX是SET if Not eXists的缩写。

1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功

2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败

3、 客户端A执行代码完成,删除锁

4、 客户端B在等待一段时间后在去请求设置key的值,设置成功

5、 客户端B执行代码完成,删除锁

$redis->setNX($key, $value);
$redis->expire($key, $ttl);

具体使用命令:

redis> SETNX keyName value
(integer) 1 

设置成功,返回1;设置失败,返回0

3、SET

上面两种方法都有一个问题,会发现,都需要设置 key 过期。

那么为什么要设置key过期呢?

如果请求执行因为某些原因意外退出了,导致创建了锁但是没有删除锁,那么这个锁将一直存在,以至于以后缓存再也得不到更新。

于是乎我们需要给锁加一个过期时间以防不测。

但是借助 Expire 来设置就不是原子性操作了。

所以还可以通过事务来确保原子性,但是还是有些问题,所以官方就引用了另外一个,使用 SET 命令本身已经从版本 2.6.12 开始包含了设置过期时间的功能。

1、 客户端A请求服务器设置key的值,如果设置成功就表示加锁成功

2、 客户端B也去请求服务器设置key的值,如果返回失败,那么就代表加锁失败    

3、 客户端A执行代码完成,删除锁    

4、 客户端B在等待一段时间后在去请求设置key的值,设置成功

5、 客户端B执行代码完成,删除锁

$redis->set($key, $value, array('nx', 'ex' => $ttl));  //ex表示秒

具体使用:

redis>set key value NX EX max-lock-time 实现加锁    

命令解释:

  • key:key就是redis的key值作为锁的标识,value在这里作为客户端的标识,只有key-value都比配才有删除锁的权利【保证安全性】
  • max-lock-time:通过max-lock-time设置过期时间保证不会出现死锁【避免死锁】
  • NX:只有这个key不存才的时候才会进行操作,if not exists;
  • EX:设置key的过期时间为秒,具体时间由第5个参数决定

加锁代码: 

 Jedis jedis = new Jedis("127.0.0.1", 6379);
 private static final String SUCCESS = "OK";
 /**
  * 加锁操作
  * @param key 锁标识
  * @param value 客户端标识
  * @param timeOut 过期时间
  */
  
 public Boolean lock(String key,String value,Long timeOut){
     String var1 = jedis.set(key,value,"NX","EX",timeOut);
     if(LOCK_SUCCESS.equals(var1)){
         return true;
     }
     return false;
 }

解锁代码:

 Jedis jedis = new Jedis("127.0.0.1", 6379); 
 private static final Long UNLOCK_SUCCESS = 1L;
 /**
  * 解锁操作
  * @param key 锁标识
  * @param value 客户端标识
  * @return
  */
  
 public static Boolean unLock(String key,String value){
     String luaScript = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return 
     redis.call(\"del\",KEYS[1]) else  return 0 end";
     Object var2 = jedis.eval(luaScript,Collections.singletonList(key), Collections.singletonList(value));
     if (UNLOCK_SUCCESS == var2) {
         return true;
     }
     return false;
}

luaScript 这个字符串是个lua脚本,代表的意思是如果根据key拿到的value跟传入的value相同就执行del,否则就返回0【保证安全性】

jedis.eval(String,list,list);这个命令就是去执行lua脚本,KEYS的集合就是第二个参数,ARGV的集合就是第三参数【保证解锁的原子操作】

上述就实现了怎么使用redis去正确的实现分布式锁,但是有个小缺陷就是锁过期时间要设置为多少合适,这个其实还是需要去根据业务场景考量一下的。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Redis实现分布式锁的几种方法总结

    Redis实现分布式锁的几种方法总结

    这篇文章主要介绍了Redis实现分布式锁的几种方法总结的相关资料, Redis实现与Zookeeper实现和数据库实现,需要的朋友可以参考下
    2017-07-07
  • Redis常用数据类型命令实例汇总

    Redis常用数据类型命令实例汇总

    这篇文章主要介绍了Redis常用数据类型命令实例汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Redis数据过期策略的实现详解

    Redis数据过期策略的实现详解

    最近项目当中遇到一个需求场景,需要清空一些存放在Redis的数据,本文对Redis的过期机制简单的讲解一下,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Redis使用ZSET实现消息队列的项目实践

    Redis使用ZSET实现消息队列的项目实践

    本文主要介绍了Redis使用ZSET实现消息队列的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Redis安装与使用方法小结

    Redis安装与使用方法小结

    这篇文章主要介绍了Redis安装与使用方法,结合实例形式分析了Redis数据库的下载、安装、启动、设置及相关使用操作注意事项,需要的朋友可以参考下
    2018-04-04
  • Redis高并发分布锁的示例

    Redis高并发分布锁的示例

    在分布式系统中,实现分布式锁是一项常见的需求,本文主要介绍了Redis高并发分布锁的示例 ,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Redis获取某个大key值的脚本实例

    Redis获取某个大key值的脚本实例

    这篇文章主要给大家分享介绍了关于Redis获取某个大key值的一个脚本实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04
  • 浅析Redis底层数据结构Dict

    浅析Redis底层数据结构Dict

    Redis是一个键值型的数据库,我们可以根据键实现快速的增删改查,而键与值的映射关系正是通过Dict来实现的,当然 Dict 也是 Set Hash 的实现方式,本文就详细带大家介绍一下Redis底层数据结构 Dict,,需要的朋友可以参考下
    2023-05-05
  • 详解Redis使用认证密码登录

    详解Redis使用认证密码登录

    本篇文章主要介绍了详解Redis使用认证密码登录 。启用Redis的认证密码可以增加Redis服务器的安全性。有兴趣的可以了解下
    2017-06-06
  • Redis 的内存淘汰策略和过期删除策略的区别

    Redis 的内存淘汰策略和过期删除策略的区别

    这篇文章主要介绍了Redis 的内存淘汰策略和过期删除策略的区别,Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略
    2022-07-07

最新评论