如何在不影响剩余 TTL 的情况下更新 redis 值?

Posted

技术标签:

【中文标题】如何在不影响剩余 TTL 的情况下更新 redis 值?【英文标题】:How can I update a redis value without affecting the remaining TTL? 【发布时间】:2014-03-20 18:40:27 【问题描述】:

是否可以在不删除现有 ttl 的情况下 SET redis 键?目前我知道的唯一方法是找出 ttl 并执行SETEX,但这似乎不太准确。

【问题讨论】:

【参考方案1】:

根据 Redis documentation 的说法,SET 命令会移除 TTL,因为密钥已被覆盖。

但是,您可以使用 EVAL 命令来评估 Lua 脚本以自动为您完成。

下面的脚本会检查键的 TTL 值,如果该值为正,它会使用新值调用 SETEX 并使用剩余的 TTL。

local ttl = redis.call('ttl', ARGV[1]) if ttl > 0 then return redis.call('SETEX', ARGV[1], ttl, ARGV[2]) end

例子:

> 设置键 123

好的

> 过期密钥 120

(整数)1

...几秒钟后

> ttl 键

(整数)97

> eval "local ttl = redis.call('ttl', ARGV[1]) if ttl > 0 then return redis.call('SETEX', ARGV[1], ttl, ARGV[2]) end" 0键987

好的

> ttl 键

96

> 获取密钥

“987”

【讨论】:

【参考方案2】:

KEEPTTL 选项将被添加到 redis>=6.0

中的 SET

https://redis.io/commands/set

https://github.com/antirez/redis/pull/6679

The SET command supports a set of options that modify its behavior:

EX seconds -- Set the specified expire time, in seconds.
PX milliseconds -- Set the specified expire time, in milliseconds.
NX -- Only set the key if it does not already exist.
XX -- Only set the key if it already exist.
(!) KEEPTTL -- Retain the time to live associated with the key.

【讨论】:

【参考方案3】:

也许INCRINCRBYDECR等可以帮到你。他们不会修改 TTL。

> setex test 3600 13
OK

> incr test
(integer) 14

> ttl test
(integer) 3554

http://redis.io/commands/INCR

【讨论】:

这对我来说非常有效,因为我正在处理整数值。【参考方案4】:

可以通过使用SETBIT根据新值逐位更改值位来更改值而不影响其键上的TTL。

然而,这种方法的缺点显然是会影响性能,尤其是在价值相当大的情况下。

注意:建议在事务(多执行)块中执行此操作

自行维护TTL

获取当前 TTL

设置新值

设置值后恢复TTL

由于所执行命令的持久性未知,显然不建议使用。

另一种选择是使用 List 作为数据类型,在使用 LPUSH 向列表添加新值后,使用 LTRIM 将列表的大小保持为单个元素。这不会改变密钥上的 TTL。

【讨论】:

【参考方案5】:

这是一个检查现有 TTL 并在需要时使用它的函数。

过期参数 0 - 使用现有的过期时间,>0 - 设置新的过期时间,未定义 - 没有过期时间。

    /**
       * update an item. preserve ttl or set a new one
       * @param object handle the redis handle
       * @param string key the key
       * @param * content the content - if an object it'll get stringified
       * @param number||null expire if a number > 0 its an expire time, 0 
means keep existing ttl, undefined means no expiry
       * @return Promise
       */
      ns.updateItem = function (handle , key , content,expire) 

        // first we have to get the expiry time if needed
        return (expire === 0 ? handle.ttl(key) : Promise.resolve (expire))
        .then (function (e) 

          // deal with errors retrieving the ttl (-1 no expiry, -2 no existing record)
          var ttl = e > 0 ? e :  undefined;

          // stingify the data if needed
          var data = typeof content === "object" ? JSON.stringify(content) : content;

          // set and apply ttl if needed
          return ttl ? handle.set (key, data , "EX", ttl) : handle.set (key,data);
        );
      ;

【讨论】:

【参考方案6】:

有一种方法可以从 Redis 获取剩余的 TTL。

Redis中维护TTL

    获取当前TTL 设置新值 设置值后恢复TTL

示例:

// This function helps to get the  Remaining TTL from the redis.
        const  getRemainingTTL=(key)=>   
            return new Promise((resolve,reject)=>
                redisClient.TTL(key,(err,value)=>
                    if(err)reject(err);
                    resolve(value);
                );
            );
        ;
     let remainingTTL=await getRemainingTTL(otpSetKey);
     console.log('remainingTTL',remainingTTL);

     redisClient.set(key,newValue,'EX',exTime ); // set agin

【讨论】:

以上是关于如何在不影响剩余 TTL 的情况下更新 redis 值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不影响之后的提交的情况下编辑旧提交

如何在不更改用户设置的缩放比例的情况下更新地图标记?

redis乐观锁

Redis 的五大数据类型和 TTL

如何在不影响设备音量的情况下使用 MPMusicPlayerController 更改音量

如何在不影响背景的情况下更改网页内容?