redis 如果 key 存在则设置值,如果不存在则不设置

问题描述 投票:0回答:1

我想确保当我使用

set
设置值时,该键必须存在

PHP 的假代码:

    $expired_at = strtotime(date('Y-m-d')) + 24 * 3600;
    $key = "store_of_today";
    $left = $redis->get($key);
    if ($left === null) {
        $redis->set($key, 100);
        $redis->expireat($key, $expired_at);
        $left = 100;
    }

    // something run ...

    // here, I must ensure that the key is exist
    // for example, I got the value by using $redis->get($key)  at 23:59:59:999;
    // then the code run over 1ms, and now is 00:00:00:015 (run 16ms here)
    // the key is expired, so I can't set data to redis
    // even though I used $redis->exist($key) to check the key is exist or not,
    // but this code still need time to run, so I can't ensure the key is exist
    $redis->set($key, $new_left);

我知道redis有

setnx
,好像没有像
setifexist

那样的功能
php redis
1个回答
0
投票

一年后,我找到了一种用 LUA 脚本解决这个问题的方法

$get_lua = <<<LUA
local key = KEYS[1]
local expireAt = ARGV[1]

local value = redis.call('GET', key)
if value == false then
    redis.call('SET', key, 100)
    redis.call('EXPIREAT', key, expireAt)
    value = 100
end

return value
LUA;


$set_lua = <<<LUA
local key = KEYS[1]
local value = ARGV[1]
local expireAt = ARGV[2]

redis.call('SET', key, value)
redis.call('EXPIREAT', key, expireAt)
LUA;

$redis = new Redis();

$expired_at = strtotime(date('Y-m-d')) + 864000; // end of today
$key = "store_of_today";
$left = $redis->eval($get_lua, [$key, $expired_at], 1);

// code

$redis->eval($set_lua, [$key, $new_left, $expired_at], 1);

redis 确保 lua 脚本是原子操作,因此

$set_lua
总是会在一次原子操作中设置一个值,然后在键上设置
expireAt
,如果
expireAt
是过去的时间戳,则该键将无效。

© www.soinside.com 2019 - 2024. All rights reserved.