繁体   English   中英

节点和MySQL:无法结束连接->异步混乱

[英]Node & MySQL: Can't end connection -> Async confusion

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

当我在下面插入葡萄酒类别时,由于未使用异步函数,因此可以正常工作。 但是,当我使用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调用的回调,因为我最终在此文件中将有许多类似的调用。

我应该如何构造我的代码,以便所有查询都执行完毕并运行并运行connection.end() 对于异步向导来说,答案可能是显而易见的。

使用诺言将是这样的:

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也是异步的,则可能要使用async.each类的async.each来处理插入记录。 它有一个方便的回调函数,当插入所有记录时将调用该回调函数,因为只有在这一点上,您才想关闭连接:

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接受一个回调(使用公共Node约定function(err, result) ),该回调将在插入记录时被调用。 在上面的代码中,我直接使用了async提供的回调,这意味着一旦您的insert_into完成,它将调用async回调,表明each迭代insert_into完成。

编辑 :您可以重写insert_into所以它看起来像这样:

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

由于您不需要来自connection.query的实际结果,因此只需要传递err (而不是抛出它)。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM