一尘不染

nodejs,redis。检查密钥是否存在,如果不存在则创建新密钥

redis

我是NodeJS的新手,也许没有事件系统应该如何工作。找不到错误。请指教。我需要一个简单的任务-
检查标签,如果它不存在,则设置新密钥和有关该标签的信息。问题是-然后我第一次运行该脚本,它始终返回“键不存在”。检查redisdb键-
它会创建很多标签这是我的代码

for (x = 0; x < rows.length; x++) {
    if (rows[x].term_taxonomy_id != 1) {
        var taxonomy = findOne(rterms, rows[x].term_taxonomy_id);
        rc.exists('tag:' + taxonomy.name, function (err, rexists) {
            if (rexists == false) {
                rc.incr('tags:count', function (err, id) {
                    console.log(taxonomy.name+' not exists. result ' + rexists);
                    rc.set('tag:' + taxonomy.name,id);
                    rc.hmset('tag:' + id,
                        'id', id,
                        'title',taxonomy.name,
                        'url', taxonomy.slug
                    );
                });//incr
            }else{
                console.log(taxonomy.name+' exists!'+rexists);
            };
        });//exists
    };//ifrows
});

这是另一个例子

var tags = [
  "apple",
  "tiger",
  "mouse",
  "apple",
  "apple",
  "apple",
  "tiger",
  "mouse",
  "mouse",
];
var count =0;
Object.keys(tags).forEach (function (tag) {
  rc.get("tag:"+tags[tag],function(err,rr){
    console.log("get tag "+tags[tag]+" result code "+rr);
    if (rr == null) {
      rc.set("tag:"+tags[tag],"info",function(err,rr){
        count++;
        console.log('set tag '+tags[tag]+' '+rr+' objects count '+count);
      });
    };
  });
})

输出:

get tag apple result code null
get tag tiger result code null
get tag mouse result code null
get tag apple result code null
get tag apple result code null
get tag apple result code null
get tag tiger result code null
get tag mouse result code null
get tag mouse result code null
set tag apple OK objects count 1
set tag tiger OK objects count 2
set tag mouse OK objects count 3
set tag apple OK objects count 4
set tag apple OK objects count 5
set tag apple OK objects count 6
set tag tiger OK objects count 7
set tag mouse OK objects count 8
set tag mouse OK objects count 9

看起来nodejs仅在该“设置”命令之后执行所有“获取”命令。所以…我了解,这全都归因于异步操作。但是如何使其工作呢?


阅读 682

收藏
2020-06-20

共1个答案

一尘不染

此代码中至少有两个问题:

  • 第一个链接到Javascript关闭管理。循环的主体不会创建作用域。使用Javascript,变量的范围是在函数级别上,而不是在块级别上。您需要在循环本身中引入一些函数来强制创建适当的闭包。更多信息在这里。

  • 第二个是存在和设置命令之间的竞争条件。如果存在多个正在运行的Redis连接,并在同一键上设置命令,则可能会发生某种冲突。您应该使用setnx来执行检查并在一个原子操作中进行设置,而不是使用存在和设置。

考虑第二个示例,使用forEach解决了关闭问题,但是由于该语言的异步特性,您仍然会在set操作之前生成所有get操作。

如果您真的想对所有get和set操作进行排序(顺便说一句,速度会慢很多),那么您可以使用一些函数式编程来使用递归实现循环。

范例

该程序:

var redis = require('redis')
var rc = redis.createClient(6379, 'localhost');

var tags = [
  "apple",
  "tiger",
  "mouse",
  "apple",
  "apple",
  "apple",
  "tiger",
  "mouse",
  "mouse",
];

var count = 0;

function loop(tags) {
  function rec_loop(tags,i) {
     if ( i >= tags.length )
        return
     rc.get("tag:"+tags[i],function(err,rr) {
        console.log("get tag "+tags[i]+" result code "+rr);
        if ( rr == null ) {
           rc.set("tag:"+tags[i],"info",function(err,rr) {
              count++;
              console.log('set tag '+tags[i]+' '+rr+' objects count '+count);
              rec_loop(tags,++i)
           })
        } else
          rec_loop(tags,++i)
     })
  }
  rec_loop(tags,0)
}

loop(tags)

显示:

get tag apple result code null
set tag apple OK objects count 1
get tag tiger result code null
set tag tiger OK objects count 2
get tag mouse result code null
set tag mouse OK objects count 3
get tag apple result code info
get tag apple result code info
get tag apple result code info
get tag tiger result code info
get tag mouse result code info
get tag mouse result code info

请注意,在此示例中竞赛条件仍然存在。您应该使用setnx来实现这种检查和设置操作。

2020-06-20