Redis-py如何监视哈希键(key)的变化?

5

我正在使用redis-py通过Python与redis进行交互。我处于这样一种情况:在原子更新哈希键之前,需要检索该键上的值。查看文档时,似乎可以使用管道和WATCH命令来确定键何时更改。是否有办法在哈希内部监视一个键?还是只适用于单个键?


你好,有解决方案吗?我需要原子性地更新特定哈希键的值...整个哈希表可能会被监视,但竞争条件会非常频繁发生。 - geronime
对于单个键,我可以使用WATCH和MULTI来实现。但我还想在哈希键内实现WATCH键。 - Tamilmaran
2个回答

8
您不能直接查看哈希键,Redis目前不支持此功能。但是您可以使用额外的“锁”字符串键,并定义一个合同,根据该合同,修改哈希值的任何人都应遵循以下过程来处理任何哈希键K
  1. WATCH lock:K
  2. HGET K,保存当前值
  3. 开始MULTI。
  4. SET lock:K ""
  5. HSET K 更新的值
  6. EXEC
这将确保更新的哈希值不会同时被覆盖。
虽然这是一个Python问题,但我提供了一个实现上述合同的NodeJS函数(只是为了展示一个想法):
/**
 * Concurrently updates Redis string and hash value under the specified key.
 *
 * @param redisCli Redis client.
 * @param hashName Hash name.
 * @param objId Object ID.
 * @param transFun Cache object transformation function (i.e. a modification that we need to apply).
 * @param cbFun Callback function, to which a modified object is passed in case of success.
 */
exports.redisUpdateHashConcurrently = function(redisCli, hashName, objId, transFun, cbFun) {
    var lockKey = hashName + ':' + objId + ':lock';

    redisCli.watch(lockKey); // Step 1.

    redisCli.hget(hashName, objId, function(err, obj) { // Step 2.
        if (err) {
            redisCli.unwatch();

            cbFun && cbFun(undefined, err);

            return;
        }

        if (obj) {
            var modObj = transFun(JSON.parse(obj));
            var value = JSON.stringify(modObj);

            redisCli.multi() // Step 3.
                .set(lockKey, '') // Step 4.
                .expire(lockKey, 3)
                .hset(hashName, objId, value) // Step 5.
                .exec(function(err, replies) { // Step 6.
                    if (!replies) { // Object was modified by someone else, retry.
                        exports.redisUpdateHashConcurrently(redisCli, hashName, objId, transFun, cbFun);
                    }
                    else { // We have succeeded.
                        cbFun && cbFun(modObj, undefined);
                    }
                });
        }
        else {
            redisCli.unwatch();
        }
    });
};

请注意,您可以为您的“锁”键指定TTL,以便它们最终被删除。

1
你总是将空字符串写入lock:K,因此如果这种情况同时发生,则lock:K的值不会被更新。在这种情况下,EXEC仍然会失败吗?我的意思是在https://redis.io/topics/transactions中写道:“我们要求Redis仅在未修改任何WATCHed键的情况下执行事务”。 - mash
1
我刚刚测试了一下。是的,即使您将“lock:K”设置为相同的值,EXEC仍然失败。 - Joe Daley

0

使用MULTI如何?这样你就不需要担心在哈希表中观察键(WATCH似乎不支持,正如你所建议的那样)。


3
MULTI 命令似乎不允许您检索值、对其进行修改,然后将修改后的值重新设置回去。除非我理解错了,MULTI 命令只是将命令排队等待执行。 - whatWhat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接