2012-02-05 88 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,以便它們最終被移除。