如何在Node.js中使用redis WATCH?

How to use redis WATCH in Node.js?

背景

我有一个原子操作,我需要使用锁来防止其他客户端读取不稳定的值。

解决方案

根据官方文档,解决方法是将WATCHMULTI一起使用:

问题

现在,MULTI 的用法已记录在案,我对如何使用它有了大致的了解。

var redis = require( "redis" );
var bluebird = require( "bluebird" );
var client = redis.createClient();
var multi = client.multi();

multi.hsetAsync( "test", "array", "[1, 2]" );
multi.hgetAsync( "test", "array" );
multi.execAsync( ).then( console.log ); // [ 0, "[1, 2]" ]

我知道这是 multi 的正确实现。首先我需要创建一个客户端,然后我创建一个多查询。

我知道 multiclient 共享相同的界面,但也不清楚我使用 hgetAsync 而不是 [=18 有什么好处(如果有的话) =] 在 multi 查询中,因为我假设 multi 所做的只是将所述请求同步添加到队列中(因此我不需要 Async 变量)。

调用 multi.execAsync( ) 后,查询的执行将原子地

但我不明白 WATCH 应该如何进入这里。我在文档中找不到任何关于它的参考,没有任何关于 REDIS 拥有的乐观锁系统的信息。

问题

所以我有以下问题:

  1. MULTI 是否支持 WATCH
  2. 如果是这样,你能分享一个代码片段吗?
  3. 在此示例中使用 multi.hgetAsync( "test", "array" ); 而不是 multi.hget( "test", "array" ); 有意义吗?

答案

没有关于在 node-redis 中使用 WATCH 的文档。然而,我确实在 MDN 中找到了一组非常有用的技巧:

https://developer.mozilla.org/en-US/docs/Mozilla/Redis_Tips

总而言之,WATCH 应该像下面这样使用:

var redis  = require("redis"),
client = redis.createClient({ ... });

client.watch("foo", function( err ){
    if(err) throw err;

    client.get("foo", function(err, result) {
        if(err) throw err;

        // Process result
        // Heavy and time consuming operation here

        client.multi()
            .set("foo", "some heavy computation")
            .exec(function(err, results) {

                /**
                 * If err is null, it means Redis successfully attempted 
                 * the operation.
                 */ 
                if(err) throw err;

                /**
                 * If results === null, it means that a concurrent client
                 * changed the key while we were processing it and thus 
                 * the execution of the MULTI command was not performed.
                 * 
                 * NOTICE: Failing an execution of MULTI is not considered
                 * an error. So you will have err === null and results === null
                 */

            });
    });
});

所以,回答我的问题:

  1. 是的,虽然 watch 是在 RedisClient 原型上调用的,而不是在 Multi 原型上调用的。
  2. 上面提供的代码片段。
  3. 因为来自对象的每个方法都具有 Multi 原型 returns 对象本身,使用 Async 版本的方法没有任何好处,除了 execAsync 它允许您执行多个查询并处理 Promise 中的响应而不是回调。

重要提示

另一个非常重要的事情是 watch 仅适用于 KEYS,不适用于散列 。所以在我的例子中,你不能看散列 test 的字段 array。您可以观看整个 test 集,但不能观看特定领域。

所以,因为在我的代码中,我实际上想查看哈希上的字段。这不可能。我必须改用一个允许这样做的密钥命名系统:

var redis = require( "redis" );
var bluebird = require( "bluebird" );
var client = redis.createClient();
var multi = client.multi();

client.watchAsync( "test_array" )
    then( ( ) =>
        multi.set( "test_array", "[1, 2]" )
            .get( "test_array" )
            .execAsync( ) 
    )
    .then( console.log ); // [ 0, "[1, 2]" ]

这方面的文档真的很少,但我希望这个问题对以后的人有所帮助。


你在读这篇文章吗from the future

如果你是从未来阅读这篇文章,你现在可以享受我对 node_redis 项目的个人贡献并查看更新的文档: