节点&connection.query内部的MySQL-connection.query-对象属性不可访问

Node & MySQL - connection.query inside connection.query - Object property not accessible

本文关键字:对象 query- 属性 访问 MySQL-connection amp connection 内部 query 节点      更新时间:2023-09-26

我遇到了一个非常尴尬的问题。我创建一个池,连接到数据库,创建一个连接和查询,获取结果,做一些事情,然后我必须创建另一个连接并查询,但实际上它必须是动态的,所以我在包含数据的Array teacherHours上循环。

然后发生了更多的Code,我必须创建一个额外的循环,因为我的teacherHours数组的某些元素必须多次尝试才能从即将到来的查询中获得正确的响应。

因此,接下来是另一个循环,它应该循环与availableHours > 0一样长的时间。现在,这是一切向左发展的地方。

在第二个循环中发生了大量代码,我准备了第二个查询,调用connection.query(),在回调函数中准备了第三个查询(在做了一些其他事情之后),这实际上是Node把我赶出去的地方。

它给了我TypeError: Cannot read property 'tid' of undefined。第三次查询需要访问tid,所以我尝试像以前一样访问它,但Node不允许。

我知道查询返回有用的数据(行),所以查询但不接收数据不会成为问题。事实上,我console.log("the rowRIDS"+rowRIDS);是第二个查询的结果,我看到它返回了2行,就在那之后,它给了我错误。

对我来说也很奇怪的是,我的两个循环中的所有console.log都被记录了下来,而我的第二个查询的console.log(包含2行)在循环结束后被记录了起来,因为查询是嵌套的,返回的2行和错误不应该出现在循环的第一次迭代中,因为代码应该在那时访问第二个询问。

顺便说一句,我试图设置一个硬编码的数字而不是tid,只是为了让下一个属性datum出错。我有点觉得变量teacherHours超出了范围,但它应该是一个全局变量。

为了更好地理解我所说的内容,我复制了代码并取消了所有javascript代码的注释,在这里我填充和计算内容。任何帮助都会非常好,它已经尝试了将近7个小时;没有任何运气的错误。非常感谢。

 pool.getConnection(function(err, connection){
  if (err) throw err;
  connection.query('SELECT * FROM teachers_teaching_tbl WHERE fwdid = 1 ', function(err, rows, fields) {  
    if (err) {
      console.error('error querying: ' + err.stack);
      return;
    } 
    rowArray=rows;
    console.log(rowArray);
    // 
    // HERE HAPPENS
    // A LOOOOT OF STUFF
    // 
    // AND teacherHours IS BEING POPULATED
    // 
    // THEN COMES A FOR LOOP 
    for(var i=0; i<teacherHours.length;i++){
      //
      // MORE STUFF
      //
      //AND ANOTHER LOOP
      while(availableHours>0){//do{ ORIGINALLY I TRIED WITH A DO WHILE LOOP
        //
        // AGAIN A BUNCH OF STUFF
        //
        // NOW I'M PREPARING MY NEXT QUERY 
        // 
        var myQueryGetFreeRoom=" SELECT rms.rid FROM rooms_tbl as rms WHERE NOT EXISTS ( "; 
        myQueryGetFreeRoom+=" SELECT NULL FROM classes_tbl as cls  "; 
        myQueryGetFreeRoom+="  WHERE ( (cls.bis > '"+bisMinus1+"' AND cls.bis <= '"+realBis+"' ) OR ( cls.von > '"+bisMinus1+"' AND cls.von < '"+realBis+"' ) ) AND (cls.datum = '"+teacherHours[i].datum.getFullYear()+"-"+(teacherHours[i].datum.getMonth()+1)+"-"+teacherHours[i].datum.getDate()+"') AND (cls.rid=rms.rid)  )  ";
        //
        //
        connection.query(myQueryGetFreeRoom, function(err, rowRIDS, fields) { 
          if (err) {
            console.error('error querying: ' + err.stack);
            return;
          }
          roomIDs=rowRIDS;
          console.log("the rowRIDS"+rowRIDS);
          //
          // MORE STUFF 
          // HAPPENING
          //
          if(roomIDs.length>0){
            //
            // PREPARING QUERY NO.3 - WHICH IS WHERE MY ERROR POINTS - TO THE USE OF tid PROPERTY
            //
            var myQueryBookClass = " INSERT INTO classes_tbl ( rid , tid , belegtAnz, datum, von , bis )  ";
            myQueryBookClass+="  VALUES ( "+Math.floor(Math.random() * roomIDs.length)+", "+teacherHours[i].tid+" , 0, '"+teacherHours[i].datum.getFullYear()+"-"+(teacherHours[i].datum.getMonth()+1)+"-"+teacherHours[i].datum.getDate()+"' , '"+bisMinus1+"' , '"+realBis+"' ) ";
            console.log("myQueryBookClass: "+myQueryBookClass);
            availableHours = 0;
            //
            // HERE WAS SUPPOSED TO FOLLOW QUERY 3 - myQueryBookClass 
            // 
            // BUT SINCE I DONT EVEN GET INSIDE HERE IT IS IN COMMENTS
            // 
            /*connection.query(myQueryBookClass, function(err, insertRows, fields){
              if(err){
                console.error('error querying: '+err.stack);
                return;
                }
              console.log("Inserted Rows: "+ insertRows);
            }); */
          } else { 
            availableHours= availableHours - 1;
            //
            // STUFF HAPPENING
            //
          } 
        });
        availableHours= availableHours - 1;  
      }//while(availableHours>0); 
    //
    }
    connection.release(function(err){
              if (err){
                console.error('error disconnecting: ' + err.stack);
                return;
              }
    });
  });
});

我认为您来自Python、Java等非异步语言。这就是为什么Node(即JavaScript)似乎会给您带来麻烦,但实际上并非如此。

代码中的问题是在同一个while循环中同时同步执行类似query的异步函数。您需要使用像async这样的模块,它可以帮助异步运行和收集结果。

这是更新后的代码。

var async = require('async'),
    connection;
async.waterfall([
    function (cb) {
        pool.getConnection(cb);
    },
    function (conn, cb) {
        connection = conn;
        connection.query('SELECT * FROM teachers_teaching_tbl WHERE fwdid = 1', cb);
    },
    function (rows, fields, cb) {
        rowArray = rows;
        console.log(rowArray);
        // HERE HAPPENS
        // A LOOOOT OF STUFF
        // 
        // AND teacherHours IS BEING POPULATED
        // 
        // THEN COMES A FOR LOOP
        async.eachSeries(teacherHours, function (teacherHour, done) {
          // MORE STUFF
          //
          //AND ANOTHER LOOP
          async.whilst(function () {
            return availableHours > 0;
          }, function (cb) {
            // AGAIN A BUNCH OF STUFF
            //
            // NOW I'M PREPARING MY NEXT QUERY 
            // 
            var myQueryGetFreeRoom =
                "SELECT rms.rid FROM rooms_tbl AS rms WHERE NOT EXISTS ("
                    + "SELECT NULL FROM classes_tbl AS cls"
                    + " WHERE ("
                        + "(cls.bis > '" + bisMinus1 + "' AND cls.bis <= '" + realBis + "')"
                        + " OR (cls.von > '" + bisMinus1 + "' AND cls.von < '" + realBis + "')"
                    + ") AND ("
                        + "cls.datum = '" + teacherHour.datum.getFullYear() + "-" + (teacherHour.datum.getMonth() + 1) + "-" + teacherHour.datum.getDate() + "'"
                    + ") AND cls.rid = rms.rid";
            async.waterfall([
                function (cb) {
                    connection.query(myQueryGetFreeRoom, cb);
                },
                function(rowRIDS, fields, cb) {
                    roomIDs = rowRIDS;
                    console.log("the rowRIDS" + rowRIDS);
                    //
                    // MORE STUFF 
                    // HAPPENING
                    //
                    if (roomIDs.length > 0) {
                        //
                        // PREPARING QUERY NO.3 - WHICH IS WHERE MY ERROR POINTS - TO THE USE OF tid PROPERTY
                        //
                        var myQueryBookClass = "INSERT INTO classes_tbl (rid, tid, belegtAnz, datum, von, bis) VALUES ("
                                + Math.floor(Math.random() * roomIDs.length) 
                                + ", " + teacherHour.tid 
                                + ", 0, '" + teacherHour.datum.getFullYear() + "-" + (teacherHour.datum.getMonth() + 1) + "-" + teacherHour.datum.getDate() + "', '" + bisMinus1 + "', '" + realBis + "')";
                        console.log("myQueryBookClass: " + myQueryBookClass);
                        availableHours = 0;
                        //
                        // HERE WAS SUPPOSED TO FOLLOW QUERY 3 - myQueryBookClass 
                        // 
                        // BUT SINCE I DONT EVEN GET INSIDE HERE IT IS IN COMMENTS
                        // 
                        connection.query(myQueryBookClass, function (err, insertRows, fields) {
                            if (err) {
                                console.error('error querying: '+err.stack);
                                return;
                            }
                            console.log("Inserted Rows: "+ insertRows);
                            // Here do whatever you need to do, then call the callback;
                            cb();
                        }); 
                    } else {
                        --availableHours;
                        //
                        // STUFF HAPPENING
                        //
                        cb();
                    } 
                }
            ], function (err) {
                if (!err) {
                    // Notice that you are decrementing the `availableHours` twice here and above.
                    // Make sure this is what you want.
                    --availableHours;
                } 
                cb(err);
            });
          }, done);
        }, function (err) {
            connection.release(function (err) {
              if (err) {
                console.error('error disconnecting: ' + err.stack);
                return;
              }
            });
        });
    }
], function (err) {
    conn && pool.release(conn);
    err && throw err;
});

下次请正确格式化代码以获得更好的可读性,这将有助于您更快地获得答案,并出于同样的目的将问题文本拆分为段落。

解释

有四个嵌套的async流:

async.waterfall
  -> async.eachSeries
     -> async.whilst
        -> async.waterfall
  1. 基本上,async.waterfall库允许您执行一系列函数。

    • 每个下一个函数将仅在前一个函数返回响应后执行
    • 为了指示一个函数已经完成并且结果可用,它必须调用回调,在我们的例子中它是cb(你可以随意调用它,例如callback)。规则是调用它,否则,下一个函数将永远不会执行,因为上一个函数似乎还没有完成它的工作
    • 一旦上一个函数完成,它就会调用具有以下签名的cb

      cb(err, connection);
      
    • 如果在请求连接时出现错误,则整个async.waterfall将中断,并执行最终的回调函数。

    • 如果没有错误,连接将作为第二个参数提供。async模块将上一个函数的所有自变量作为第一、第二等自变量传递给下一个函数,这就是为什么第二个函数接收conn作为第一自变量的原因
    • 每个下一个函数都将接收回调cb作为最后一个参数,您最终必须在作业完成时调用它。

    • 因此,在第一个async.waterfall流中:

      1. 它请求一个新的数据库连接
      2. 一旦连接可用,将执行下一个函数,该函数将向数据库发送查询
      3. 等待查询结果,然后一旦结果可用,就可以运行下一个函数,该函数对每一行进行迭代
  2. async.eachSeries允许按顺序迭代给定的值数组。

    • 在第二个async.eachSeries流中:

      1. 它按顺序迭代teacherHours数组中的每个元素
      2. 一旦处理了每个元素(无论您想要什么),就必须调用done回调。同样,您可以像前面的async.waterfallcallback一样将其称为cbdone只是为了清楚起见,该过程已完成
  3. 然后我们有了async.whilst,它提供了与普通while () {}语句相同的逻辑,但异步处理循环。

    • 在第三个async.whilst流中:

      1. 调用第一个函数。它的返回值指示它是否必须继续循环,即调用第二个异步函数
      2. 如果返回值是trustavailableHours > 0),则调用第二个函数
      3. 当异步函数完成时,它必须调用所提供的回调cb来指示它已经结束。然后async模块将调用第一个函数来检查是否必须继续循环
  4. async.whilst中的这个异步函数中,我们有另一个async.waterfall,因为您需要为每个teacherHour向数据库发送查询。

    • 在最后的第四个async.watercall流中:

      1. 它向数据库发送SELECT查询
      2. 正在等待响应。一旦rowRIDS可用,它就调用waterfall中的第二个函数
      3. 如果存在rowRIDSroomIDs.length > 0),则向数据库发送INSERT查询
      4. 一旦完成,它调用回调cb
      5. 如果没有rowRIDs,它也会调用回调cb,以指示作业已完成

JavaScript是异步的,这是一件很棒的事情。当你从其他同步语言转换时,一开始可能会很困难,但一旦你有了这个想法,就很难同步处理。它变得如此直观,以至于你会开始思考为什么其他语言不能异步工作。

我希望我能彻底解释上面的代码。享受JavaScript!太棒了!