2015-05-01 51 views
3

我正在使用iojs和node-mysql。這是我第一次進入異步服務器端編程。它基本上是一個批處理作業:運行一次,退出。我特意試圖在一張充滿版本的表格上做到這一點:如何在不斷開連接的情況下在node.js mysql中使用遞歸?

對於過去一年中編輯的每個文檔;該文件在過去一年中的每次修訂;獲得之前的修訂並將其內容與當前版本進行比較。

所以,我用一個查詢(每個文檔)的結果,以火過的其他查詢任意數量(每個修訂),必須自己遞歸(獲得前修訂) 。

我想不出如何關閉數據庫連接。據我所知,遞歸是混雜因素:如果我從代碼中刪除它,那麼我可以關閉數據庫連接。但我需要緩解。

這是一個最小的例子(假設需求和配置都OK),它完成了我在程序中看到的行爲。

var con = mysql.createConnection(db_config); 
con.connect(); 

con.query('SELECT field_2 FROM test_table', function(err, rows) { 
    if (err) throw err; 
    rows.forEach(function(row) { 
     second_query(row.field_2); 
    }); 

    // using this here works if there is no recursion, even if second_query runs long 
    // using this here does not work if there is recursion 
    // removing this allows the program to run to completion, but the event loop never exits 
    con.end() 
}); 

function second_query(key) { 
    con.query('SELECT * FROM test_table_2 WHERE field_2 > ?', [key], function(err, rows) { 
     if (err) throw err; 
     if (rows.length > 0) { 
      rows.forEach(function(row) { 
       console.log(row.field_2); 
      }); 
      second_query(key + 1); 
     } 
    }); 
} 

我已經很努力在累加器註冊數據庫查詢和每個查詢結束遞減蓄電池來解決問題,但是這並沒有產生可預測的成功,但它使代碼的痛苦與合作。

回答

3

我喜歡async.queue這種類型的工作量。你可以免費獲得平凡可調的併發性,但它總是最容易併發1.

var mysql = require("mysql"); 

// concurrency 1. Adjust to taste once it's working 
var queue = require("async").queue(secondQuery, 1); 
var dbOptions = { 
    host: process.env.DOCKER_IP, 
    database: "hoosteeno", 
    user: "root", 
    password: "password" 
}; 
var con = mysql.createConnection(dbOptions); 
con.connect(); 

con.query("SELECT field_2 FROM test_table", function (error, rows) { 
    if (error) throw error; 
    rows.forEach(function (row) { 
    queue.push(row.field_2); 
    }); 
}); 

function secondQuery (key, callback) { 
    var sql = "SELECT * FROM test_table_2 WHERE field_2 > ?"; 
    con.query(sql, [key], function (error, rows) { 
    if (error) { 
     callback(error); 
     return; 
    } 
    if (rows.length > 0) { 
     rows.forEach(function (row) { 
     console.log(row.field_2); 
     }); 
     queue.push(key + 1); 
    } 
    callback(); 
    }); 
} 

queue.drain = function() { 
    con.end(); 
}; 
+0

我喜歡這個答案,很乾淨:)。 'drain'函數是否帶有err參數?或者排隊激發錯誤事件? –

+1

不,錯誤必須在發生時適當地處理,您可以選擇允許隊列繼續,暫停,終止等等。我不認爲有任何關於錯誤處理的假設。 https://github.com/caolan/async/blob/master/lib/async。js#L731 –

1

調試,我認爲當你所有的異步SQL查詢的完成您的問題是圍繞檢測。我在這裏有幾個想法。

下面是一個(免責聲明:未經測試!)方法,不會更改您的代碼結構太多。我使用allQueriesRan來跟蹤您的所有查詢何時發佈,我使用pendingQueries作爲計數器來跟蹤我們仍在等待的查詢數量。

var allQueriesRan = false; 
var pendingQueries = 0; 

function second_query(key) { 
    pendingQueries++; 
    con.query('SELECT * FROM test_table_2 WHERE field_2 > ?', [key], function(err, rows) { 
     pendingQueryies--; 
     if (allQueriesRan && pendingQueries === 0) { 
      // We've finished our recursion and we've allowed all queries to return 
      con.end(); 
     } 

     if (err) throw err; 
     if (rows.length > 0) { 
      rows.forEach(function(row) { 
       console.log(row.field_2); 
      }); 

      second_query(key + 1); 
     } else { 
      allQueriesRan = true; 
     } 
    }); 
} 

承諾庫也可能使你的代碼簡潔,如果你願意下降到那個兔子洞。我喜歡kriskowal/Q。 Q例如允許你讓你的遞歸函數返回一個promise對象,以後可以「解決」,也就是說,一旦你的所有查詢都返回了。您可以通過呼叫.then()來鎖定該承諾,以在正確的時間關閉數據庫連接。這裏是你的代碼可能看起來像使用這種方法:

var deferred = Q.defer(); 

function second_query(key) { 
    con.query('SELECT * FROM test_table_2 WHERE field_2 > ?', [key], function(err, rows) { 
     if (err) { 
      return deferred.reject(err); 
     } 

     if (rows.length > 0) { 
      rows.forEach(function(row) { 
       console.log(row.field_2); 
      }); 

      second_query(key + 1); 
     } else { 
      deferred.resolve(); 
     } 
    }); 

    return deferred.promise; 
} 

second_query(yourKey) 
    .then(function() { 
     console.log('All done!'); 
    }) 
    .fail(err, function(err) { 
     throw err; 
    }) 
    .finally(function() { 
     con.end(); 
    }); 

需要注意的是這方面的一個方便的功能是查詢是否曾經返回err,調用deferred.reject()隨意短路您的.fail()處理程序的執行流程最底部。

+0

非常感謝 - 當我要使用Peter Lyons解決方案時,您的回答幫助我瞭解了更多關於Node.js中的編程的內容。非常感謝! – hoosteeno

相關問題