2012-02-05 82 views
3

我正在使用redis-py通过python与redis进行接口。我处于这种情况,我需要自动更新散列键,但首先需要检索该键的值,然后才能更新它。通过文档查看,我可以使用管道和WATCH命令来确定密钥何时发生更改。无论如何要看一个哈希密钥?或者这只适用于单数键?redis-py手表哈希键

+0

你好,任何解决方案?我需要自动更新特定哈希键的值以及...整个哈希值可能会被监视,但竞态条件会非常频繁地发生。 – geronime 2012-10-18 21:51:40

+0

对于单数键我可以通过WATCH和MULTI来完成。但我也希望在一个散列键中实现WATCH键。 – 2013-09-27 08:44:02

回答

0

如何使用MULTI?那么你不需要担心看到哈希中的一个键(这个WATCH看起来不支持,正如你所建议的那样)。

+0

它看起来不像MULTI允许你检索一个值,修改它,然后设置值。除非我错了MULTI只是排队命令。 – whatWhat 2012-02-06 15:08:20

1

您不能直接观看哈希键,目前Redis不支持这种方式。但是你可以使用额外的“锁定”字符串键,并定义了合同,由任何人,谁修改您的哈希值,应遵循以下任何散列键K的过程:

  1. WATCH lock:K
  2. HGETķ ,保存当前值
  3. 启动MULTI。
  4. SET lock:K “”
  5. HSETķupdated_value
  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,以便它们最终被移除。