【问题标题】:How to use redis WATCH in Node.js?如何在 Node.js 中使用 redis WATCH?
【发布时间】:2018-11-15 21:16:50
【问题描述】:

背景

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

  • 平台:节点 10.1.0
  • 图书馆redis

解决方案

根据官方文档,解决方案是使用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 共享相同的界面,但也不清楚在multi 查询中使用hgetAsync 而不是hget 有什么好处(如果有的话),因为我假设 multi 所做的只是将所述请求同步添加到队列中(因此我不需要 Async vartiant )。

在调用multi.execAsync( ) 时,查询的执行将自动发生。

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

问题

所以我有以下问题:

  1. WATCH 支持 MULTI 吗?
  2. 如果可以,可以分享一下代码 sn-p 吗?
  3. 在这个例子中使用multi.hgetAsync( "test", "array" ); 代替multi.hget( "test", "array" ); 有意义吗?

【问题讨论】:

    标签: javascript node.js redis node-redis


    【解决方案1】:

    回答

    没有关于在 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. 上面提供了代码 sn-p。
    3. 因为来自具有Multi 原型的对象的每个方法都返回对象本身,使用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 项目的个人贡献并查看更新的文档:

    【讨论】:

    • 使用同一个redis客户端是否有可能出现竞态条件?例如,我正在考虑使用 async.parallel 运行相同的 MULTI。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多