2016-01-04 78 views
0

我有一個相當尷尬的問題。我創建一個池,連接到數據庫,創建一個連接和查詢,獲得結果,做了一堆東西,然後我必須創建另一個連接和查詢,但實際上它必須是動態的,所以我循環我的數組中包含數據的teacherHours節點和MySQL - connection.query裏面connection.query - 對象屬性不可訪問

然後更多的代碼正在發生,我必須創建一個額外的循環,因爲我的teacherHours數組中的某些元素必須多次嘗試才能從即將到來的查詢中獲得正確的響應。

因此,另一個循環如下,它應該循環,只要availableHours > 0。現在,這裏就是一切。

一批代碼發生在第二個循環內部,我準備第二個查詢,調用connection.query()和回調函數內部我準備我的第三個查詢(在做了其他一些事情之後),這實際上是Node踢我出去。它可以給我TypeError: Cannot read property 'tid' of undefinedtid需要爲我的第三個查詢進行訪問,所以我嘗試訪問它,就像我之前做的,但節點不允許它。

我知道查詢返回有用的數據(行),所以它不能成爲查詢但沒有收到數據的問題。其實我console.log("the rowRIDS"+rowRIDS);第二個查詢的結果,我看到它返回2行,然後它給了我錯誤。

對我來說也很奇怪,我的兩個循環中的所有console.logs都被記錄下來,而且我的第二個查詢(包含2行)的console.log在循環運行之後被記錄下來,因爲查詢嵌套不應該返回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; 
       } 
    }); 
    }); 
}); 
+0

順便說一句。最初我不想使用'availableHours = availableHours - 1; '在第二個'connection.query()'之後,我只想在第二個'connection.query()'中使用它。但是,如果我這樣做,我會得到一個無限循環,並且第二個'connection.query()'永遠不會進入..怪異 – b101

回答

3

我想你是從像Python,Java等非異步語言這就是爲什麼節點,即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回調。再次,您可以將此稱爲cb,如前面的async.waterfallcallbackdone只是爲了清楚,過程是完成
  3. 然後我們提供了相同的邏輯正常while() {}語句,但異步處理循環的async.whilst

    • 在該第三async.whilst流量:

      1. 調用第一功能。其返回值指示是否必須繼續循環,即調用第二個異步函數。
      2. 如果返回值爲如實availableHours > 0),則調用第二個函數。
      3. 當異步函數完成後,它必須調用提供的回調cb來指示它已結束。然後async模塊將調用第一個函數來檢查是否必須繼續循環。
  4. 在這個異步函數裏面async.whilst我們有另一個async.waterfall,因爲你需要發送查詢到數據庫中的每個​​。

    • 在這最後的第四async.watercall流量:

      1. 它發送SELECT查詢數據庫。
      2. 等待響應。一旦rowRIDS可用,它將調用waterfall中的第二個函數。
      3. 如果有rowRIDSroomIDs.length > 0),它會將INSERT查詢發送到數據庫。
      4. 完成後,它會調用回調cb
      5. 如果沒有rowRIDs,它也會調用回調cb來指示作業已完成。

這是一個偉大的事情,JavaScript是異步的。當你從其他同步語言進行轉換時,開始可能會很困難,但一旦你明白了,就很難同步。它變得非常直觀,您將開始思考爲什麼其他語言不能以異步方式工作。

我希望我能徹底解釋上面的代碼。享受JavaScript!這很棒!

+0

感謝您的幫助和輸入。你是對的,我來自C和Java。我試圖使用你的代碼(安裝了異步包並應用了更改),但Node不啓動。它用'err && throw err'把我踢出去; ^^^^^ 語法錯誤:意外的令牌throw' 你介意重新檢查skript? BTW。當它工作,這將是很好,如果你可以解釋一對夫婦的事情,因爲有一些事情我不明白安靜,甚至儘管我讀了異步包的例子。 – b101

+0

我包的最後一行'ERR &&扔犯錯;'這個'如果(ERR)拋出犯錯;'(不知道這是否是一樣的),但它的節點後啓動的。 可悲的是壽,以前outter for循環的迭代,現在'async.eachSeries()'不會繼續進行迭代。我只看到老師在屏幕上的第一個元素。爲了看看發生了什麼,我在我的javascript中創建了日誌。我在第三個查詢'myQueryBookClass'之後也做了一個。我知道我的teacherHours數組長度爲7,所以我應該看到7次迭代。 – b101

+0

我懂了!對不起,我在'if(roomIDs.length> 0){...}'裏面調用'cb();'是愚蠢的。我不想做插入到數據庫,而不是立即,我想研究代碼一點點,所以我評論了'connection.query(){...});'和'之後CB();' - 不知道它會停止迭代。所以在插入'cb();'後,一切正常。現在我也做我的插入。我真的非常感謝你的幫助。你介意給我解釋這些電話背後的邏輯嗎? – b101