节点和MySQL:不能结束连接 – >asynchronous混淆

我正在尝试编写一个Node程序,用我在磁盘上的文件中的数据填充我的MySQL数据库。 我可能会也可能不会以正确的方式进行,但是它正在工作。 我遇到的麻烦是理解我应该如何处理,允许asynchronous函数在连接到数据库之前完成。 最终,我将阅读大量的数据文件,并像下面这样将它们插入到数据库中。 我可以只使用readFileSync而不是asynchronous版本,但是我需要更好地处理asynchronous函数。

当我插入下面的葡萄酒类别时,它工作正常,因为它不使用asynchronousfunction。 但是,当我使用readFile从文件中获取数据时,出现连接在任何查询执行之前结束的错误:

 connection.connect( function(err) { if(err) { console.log(err); } }); // Take a table and the values, and insert a new row into a table function insert_into( table, values ) { if( values instanceof Array ) { values = values.map( function( value ) { return '"' + value + '"'; }).join(', '); } else { values = '"' + values + '"'; } var statement = 'INSERT INTO ' + table + ' VALUES (NULL, ' + values + ')'; connection.query( statement, function(err, rows, fields) { if (err) throw err; console.log( values + " successfully added."); }); }; // Populate the wine_categories table var wine_categories = [ 'red', 'white', 'rose', 'sparkling', 'fortified' ]; // Works fine when used alone wine_categories.forEach( function( element ) { insert_into( 'wine_categories', element ); }); // Populate the countries table // connection.end() runs before this finishes its job fs.readFile( countries, 'utf8', function (err, data) { if (err) { throw err; } else { var codes = Array.prototype.map.call( data.split('\n'), function( country ) { return country.split('\t'); }); codes.forEach( function( country ) { if( country[1].length > 25 ) { country[1] = country[1].substring(0, 25); } insert_into( 'countries', country ); }); } }); connection.end(); 

显然, connection.end()需要在所有的插入完成后发生,但我不知道如何处理。 我不希望它是readFile调用的callback,因为我最终会在这个文件中有很多类似的调用。

我应该如何构build我的代码,以便所有查询都执行,并在connection.end()完成时运行connection.end() 。 答案可能是明显的asynchronousWiz …

使用承诺它将是这样的:

 pool.getConnectionAsync().then(function(connection) { // Populate the wine_categories table var wine_categories = [ 'red', 'white', 'rose', 'sparkling', 'fortified' ]; var wineQueries = wine_categories.map(function(wine){ return insert_into(connection, "wine_categories", wine); }); var countryQueries = fs.readFileAsync(countries, "utf-8").then(function(data) { return data.split("\n").map(function(country) { country = country.split("\t")[1]; if (country.length > 25) { country = country.substring(0, 25); } return insert_into(connection, "countries", country); }); }); Promise.all(wineQueries.concat(countryQueries)) .then(function() { console.log("all done"); }) .catch(function(e) { console.log("error", e); }) .finally(function() { connection.release(); }) }); 

上述的先决条件

 var Promise = require("bluebird"); var fs = Promise.promisifyAll(require("fs")); Promise.promisifyAll(require("mysql/lib/Connection").prototype); var pool = Promise.promisifyAll(require("mysql").createPool({ "user": "...", "password": "...", "database": "...", "host": "localhost", "port": 3306, "debug": false })); function insert_into(connection, table, values) { if( values instanceof Array ) { values = values.map(connection.escape, connection).join(', '); } else { values = connection.escape(values); } return connection .queryAsync('INSERT INTO ' + table + ' VALUES (NULL, ' + values + ')') .then(function() { console.log(values + " successfully added."); }); } 

假设insert_into也是asynchronous的,你可能想使用像async.each来处理插入你的logging。 它有一个方便的callback,当所有的logging被插入时都会被调用,因为只有在那一点你想closures连接:

 async.each(codes, function(country, callback) { if ( country[1].length > 25 ) { country[1] = country[1].substring(0, 25); } insert_into( 'countries', country, callback ); // !! read below }, function(err) { // TODO: handle any errors ... // Here, all countries are inserted. connection.end(); }); 

但是,这意味着insert_into也应该接受一个callback(使用通用的Node约定function(err, result) ),这个function(err, result)将在插入logging时被调用。 在上面的代码中,我直接使用了async提供的callbackinsert_into ,这意味着一旦insert_into完成,它将调用asynccallback信号, each完成这个迭代。

编辑 :你可以重写insert_into ,看起来像这样:

 function insert_into( table, values, callback ) { ... connection.query(..., function(err) { callback(err); }); } 

既然你不需要connection.query的实际结果,你只需要通过err (而不是抛出它)。

提示:假设您正在使用node-mysql ,您可能需要查看有关如何帮助您转义的文档。