Redis - 在带有承诺的事务中插入数组中的值(蓝鸟)
Posted
技术标签:
【中文标题】Redis - 在带有承诺的事务中插入数组中的值(蓝鸟)【英文标题】:Redis - Insert values from array in a transaction with promises (bluebird) 【发布时间】:2015-07-19 23:38:08 【问题描述】:我有一个这样的数组:
var names = ['Irina', 'Michael', 'Carl'];
我想使用带有承诺的事务将它们插入到 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 次,然后执行其他方法。为什么?
【问题讨论】:
你为什么要通过回调调用getAsync
?
我已经用我所做的更改编辑了我的问题,但仍然遇到一些问题。
对于这个用例来说,最好的事情是利用 Lua 并在服务器本身内执行
【参考方案1】:
我以这种方式解决了我的问题:
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://***.com/a/25129878/2954267)
【讨论】:
【参考方案2】:免责声明:不是 JS 专家,但我会尽力帮助 :)
您似乎希望每个名称都有一个唯一的 ID。本着KISS 的精神,我会尝试执行以下不需要任何事务行为的流程:
-
id = INCR 用户:id
HMSET 用户:...
这里的“风险”是,如果您的工人在 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 事务,我猜想姓氏的更新,特别是对 INCR 的调用,会破坏以前的 WATCH。由于您没有导致错误,因此您看不到这一点。您还可以在执行代码时使用 Redis 的 MONITOR
来调试行为。
更新 2:我猜这就是 Node 异步处理的方式 - 首先它会触发 GET 并在需要等待响应时停止。然后第一个响应(对第一个 GET)得到处理,然后是第二个......除了弄乱你的预期逻辑之外,这也导致只有第一批享受 MULTI - 另外两个在他们之前没有 MULTI 语句相对 EXEC。
【讨论】:
是的,但我想用交易来做! 为什么交易有问题?为什么multi.execAsync()
不起作用?
凭直觉更新了答案
添加更多想法 - 您需要事务将所有名称包含在一起还是仅包含名称和计数器增量?
另外,没有什么比对我自己的回答投反对票更重要的了
以上是关于Redis - 在带有承诺的事务中插入数组中的值(蓝鸟)的主要内容,如果未能解决你的问题,请参考以下文章