是否可以在SET
不删除现有 ttl 的情况下重新分配密钥?我目前知道的唯一方法是找出 ttl 并做一个SETEX
,但这似乎不太准确。
6 回答
根据 Redis文档,该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 key 987
好的
> ttl 键
96
> 获取密钥
“987”
redis>=6.0 的 SET 中会添加KEEPTTL选项
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.
也许INCR
, INCRBY
,DECR
等可以帮助你。他们不会修改 TTL。
> setex test 3600 13
OK
> incr test
(integer) 14
> ttl test
(integer) 3554
通过使用SETBIT根据新值逐个更改值位,可以在不影响其键上的 TTL 的情况下更改值。
然而,这种方法的缺点显然是性能影响,尤其是在价值相当大的情况下。
注意:建议在事务(多执行)块中执行此操作
通过我们自己维护TTL
获取当前 TTL
设置新值
设置值后恢复 TTL
由于执行的命令的持久性未知,显然是不可取的。
另一种选择是使用 List 作为数据类型,在使用LPUSH向列表添加新值后,使用LTRIM将列表的大小保持为单个元素。这不会改变密钥上的 TTL。
有一种方法可以从 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 并在需要时使用它的函数。
expire arguments 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);
});
};