【问题标题】:redis-py watch hash keyredis-py 监视哈希键
【发布时间】:2012-02-05 00:15:55
【问题描述】:

我正在使用 redis-py 通过 python 与 redis 交互。我处于需要以原子方式更新哈希键但首先需要检索该键的值才能更新它的情况。查看文档,我似乎可以使用管道和 WATCH 命令来确定密钥何时更改。无论如何要观察哈希内的密钥吗?还是这只适用于单数键?

【问题讨论】:

  • 您好,有什么解决办法吗?我还需要自动更新特定哈希键的值...可能可以监视整个哈希,但竞争条件会非常频繁地发生。
  • 对于单数键,我可以通过 WATCH 和 MULTI 来完成。但我也在寻求在哈希键中实现 WATCH 键。

标签: python redis


【解决方案1】:

你不能直接查看哈希键,Redis 暂时不支持。但是你可以使用额外的“锁定”字符串键,并定义一个合约,任何修改你的哈希值的人都应该按照下面的过程来处理任何哈希键K:

  1. 观看lock:K
  2. HGET K,保存当前值
  3. 启动 MULTI。
  4. SET lock:K ""
  5. HSET K 更新值
  6. 执行

这将保证更新的哈希值不会同时被覆盖。

虽然这是一个 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,以便它们最终被删除。

【讨论】:

  • 您总是将空字符串写入lock:K,因此如果这种情况同时发生,lock:K 的值不会更新。在这种情况下,EXEC 是否仍然失败?我的意思是在redis.io/topics/transactions 中它是这样写的“我们要求 Redis 仅在没有被修改的 WATCHed 键时才执行事务”
  • 我刚刚测试过了。是的,EXEC 仍然失败,即使您将 lock:K 设置为相同的值。
【解决方案2】:

使用MULTI怎么样?那么您就不必担心查看哈希中的键(正如您所建议的那样,WATCH 似乎不支持)。

【讨论】:

  • 它看起来不像 MULTI 允许您检索一个值,修改它然后将值设置回来。除非我弄错了 MULTI 只是将命令排队。
猜你喜欢
  • 2016-02-06
  • 1970-01-01
  • 1970-01-01
  • 2012-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 2019-06-30
相关资源
最近更新 更多