Redis - 使用promises(bluebird)在事务中插入数组中的值

时间:2015-05-08 23:25:38

标签: node.js transactions redis bluebird

我有一个这样的数组:

var names = ['Irina', 'Michael', 'Carl'];

我想使用promises交易将它们插入 redis (我不知道另一种方式)。但我对如何做到这一点很困惑;这是我的代码:

var Promise = require("bluebird");
var redis = require("redis");

Promise.promisifyAll(redis.RedisClient.prototype);
Promise.promisifyAll(redis.Multi.prototype);

var client = redis.createClient(), multi;

var names = ['Irina', 'Michael', 'Carl'];

var result = names.map(function(item) {
    client.watch('user:id');
    client.getAsync('user:id', function(err, data) {
      var multi = client.multi();
      var user_id = parseInt(data) + 1;
      multi.hmsetAsync('user:' + user_id, 'username', item, 'about', 'love to coding');
      multi.incrAsync('user:id');
      multi.execAsync(function(err,data){
        console.log(data);
      });
    });
});

Promise.all(result).then(function(response) {
    console.log(response);
});

但这不起作用(:

编辑:这是应用程序抛出的错误:

未处理的拒绝错误:ERR错误的“get”命令参数数量

有人,请帮帮我!

编辑2:我已经更改了我的代码,但现在只保存了数组的最后一个值:

client.watch('user:id');
var result = names.map(function(item) {        
    var multi = client.multi();
    client.getAsync('user:id').then(function(value) {
        var user_id = parseInt(value) + 1;
        return user_id;
    }).then(function(user_id) {
        multi.hmsetAsync('user:' + user_id, 'username', item, 'about', 'love to coding');
        multi.incrAsync('user:id');
    }).then(function() {
        multi.execAsync().spread(function(err,data){
            console.log(data);
        });
    });
});

编辑3:

使用redis' MONITOR时,这是输出:

[0 127.0.0.1:54439] "info"
[0 127.0.0.1:54439] "watch" "user:id"
[0 127.0.0.1:54439] "get" "user:id"
[0 127.0.0.1:54439] "get" "user:id"
[0 127.0.0.1:54439] "get" "user:id"
[0 127.0.0.1:54439] "MULTI"
[0 127.0.0.1:54439] "hmset" "user:88" "username" "Irina" "about" "love to coding"
[0 127.0.0.1:54439] "incr" "user:id"
[0 127.0.0.1:54439] "EXEC"
[0 127.0.0.1:54439] "MULTI"
[0 127.0.0.1:54439] "hmset" "user:88" "username" "Michael" "about" "love to coding"
[0 127.0.0.1:54439] "incr" "user:id"
[0 127.0.0.1:54439] "EXEC"
[0 127.0.0.1:54439] "MULTI"
[0 127.0.0.1:54439] "hmset" "user:88" "username" "Carl" "about" "love to coding"
[0 127.0.0.1:54439] "incr" "user:id"
[0 127.0.0.1:54439] "EXEC"

执行get user:id 3次,然后执行其他方法。为什么呢?

2 个答案:

答案 0 :(得分:2)

我用这种方式解决了我的问题:

client.watch('user:id');
Promise.each(names, function(item) {
    var multi = client.multi();
    return client.getAsync('user:id').then(function(value) {
        var user_id = parseInt(value) + 1;
        return user_id;    
    }).then(function(user_id) {
        multi.hmsetAsync('user:' + user_id, 'username', item, 'about', 'love to coding');
        multi.incrAsync('user:id');
    }).then(function() {
        return multi.execAsync().spread(function(err,data){
            console.log(data);
        });
    });
})
.then(function() {
    console.log("Ended process ...");
});

诀窍是改变:

var result = names.map(function(item) {...});

承诺:

Promise.each(names, function(item) {...});

然后将client.getAsync(user:id)返回给它。

这是redis'MONITOR:

的输出
[0 127.0.0.1:53290] "info"
[0 127.0.0.1:53290] "watch" "user:id"
[0 127.0.0.1:53290] "get" "user:id"
[0 127.0.0.1:53290] "MULTI"
[0 127.0.0.1:53290] "hmset" "user:88" "username" "Irina" "about" "love to coding"
[0 127.0.0.1:53290] "incr" "user:id"
[0 127.0.0.1:53290] "EXEC"
[0 127.0.0.1:53290] "get" "user:id"
[0 127.0.0.1:53290] "MULTI"
[0 127.0.0.1:53290] "hmset" "user:89" "username" "Michael" "about" "love to coding"
[0 127.0.0.1:53290] "incr" "user:id"
[0 127.0.0.1:53290] "EXEC"
[0 127.0.0.1:53290] "get" "user:id"
[0 127.0.0.1:53290] "MULTI"
[0 127.0.0.1:53290] "hmset" "user:90" "username" "Carl" "about" "love to coding"
[0 127.0.0.1:53290] "incr" "user:id"
[0 127.0.0.1:53290] "EXEC"

太棒了,但是真的! (线索:https://stackoverflow.com/a/25129878/2954267

答案 1 :(得分:0)

免责声明:不是JS maven,但我会尝试帮助:)

看起来您希望每个名称都有一个唯一的ID。本着KISS的精神,我会尝试执行以下不需要任何事务行为的流程:

  1. id = INCR用户:id
  2. HMSET用户:...
  3. 这里的“风险”是,如果你的工人死于1& 2,你“花”一个ID。如果你可以忍受这种情况,你可能应该看起来像这样(对不起,未经测试 - 见免责声明;)):

    var result = names.map(function(item) {
        client.incrAsync('user:id').then(function(user_id) {
            client.hmsetAsync('user:' + parseInt(user_id), 'username', item, 'about', 'love to coding');
        }).then(function(err) {
            console.log(err);
        });
    });
    

    更新1 :但由于您正在修改for for,我猜测姓氏的更新,特别是对INCR的调用,打破了以前的更新的WATCH。由于您没有导致错误,因此您没有看到此错误。您还可以在执行代码时使用Redis'MONITOR来调试行为。

    更新2 :我猜这是Node如何处理异步 - 首先它会触发GET并在需要等待响应时停止。然后第一个响应(到第一个GET)被处理,然后是第二个...除了弄乱你的预期逻辑,这也导致只有第一个批量享受MULTI - 其他两个没有在他们的之前没有MULTI声明相对执行。