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

时间:2016-01-04 00:58:04

标签: javascript mysql node.js

我遇到了一个非常尴尬的问题。 我创建一个池,连接到数据库,创建连接和查询,获取结果,做一堆东西,然后我必须创建另一个连接和查询,但实际上它必须是动态的,所以我循环我的数组{ {1}}包含数据。

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

接着是另一个循环,它应该循环teacherHours。现在,这就是它的全部内容。

一堆代码发生在第二个循环中,我准备我的第二个查询,调用connection.query()和回调函数内部我准备我的第三个查询(在做了一些其他的东西之后)这实际上就是Node踢的地方我出去

它给了我availableHours > 0。我的第三个查询需要访问TypeError: Cannot read property 'tid' of undefined,因此我尝试像以前一样访问它,但Node不允许它。

我知道查询会返回有用的数据(行),因此它不会成为查询问题,但不会接收数据。实际上我tid第二个查询的结果,我看到它返回2行,就在它之后,它给了我错误。

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

顺便说一句,我尝试设置一个硬编码而不是console.log("the rowRIDS"+rowRIDS);只是为了让下一个属性tid成为错误。我有种感觉,好像变量teacherHours不在范围内,但它应该是一个全局变量。

为了更好地了解我正在谈论的内容,我复制了代码并取消注释了所有的javascript代码,我在其中填充和计算内容。任何帮助都会非常棒,经过近7个小时的尝试和尝试。没有运气的错误。谢谢!

datum

1 个答案:

答案 0 :(得分:3)

我认为你来自Python,Java等非异步语言,这就是为什么Node,即JavaScript,似乎为你搞砸了,但实际上它并不是。

您的代码中存在的问题是您在同一query循环中同时执行所有异步函数,如while。您需要使用像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回调。同样,您可以将其称为cb,就像之前的async.waterfallcallback一样。 done只是为了清楚说明该过程已完成
  3. 然后我们有async.whilst提供与普通while () {}语句相同的逻辑,但是异步处理循环。

    • 在第三个async.whilst流程中:

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

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

      1. 它将SELECT查询发送到数据库。
      2. 等待回应。 rowRIDS可用后,它会调用waterfall
      3. 中的第二个函数
      4. 如果有rowRIDSroomIDs.length > 0),则会将INSERT查询发送到数据库。
      5. 完成后,会调用回调cb
      6. 如果没有rowRIDs,它也会调用回调cb来表明作业已完成。
  5. JavaScript是异步的,这是一件好事。当你从其他同步语言转换时,开头可能很难,但是一旦你明白了,就很难同步。它变得非常直观,你会开始思考为什么其他语言不能异步工作。

    我希望我能彻底解释上述代码。享受JavaScript!真棒!