2

所以我第一次尝试使用 Node,但我无法真正理解如何使用 MySQL 连接。脚本有点像这样简化

var mysql       = require('mysql');
var connection  = mysql.createConnection({
  host     : '192.168.40.1',
  user     : 'user',
  password : 'password',
  database : 'database'
});

function DoSomething(connection, item, callback) {
    connection.query(
        'SELECT COUNT(*) AS count FROM another_table WHERE field=?', 
        item.field, 
        function (err, results) {
            if (err) throw err;

            if (results.length > 0 && results[0].count >= 1) {
                callback(err, connection, item, 'Found something')
            }
    });
}

function DoSomethingElse(connection, item, callback) {
    // Similar to DoSomething()
}

function StoreResult(err, connection, item, reason) {
    if (err) throw err;

    connection.query(
        'INSERT INTO result (item_id, reason) VALUES (?, ?)',
        [item.id, reason],
        function (err, results) {
            if (err)  throw err;
    });
}

connection.query('SELECT * FROM table WHERE deleted=?', [0], function (err, results) 
{
    if (err) throw err;

    results.forEach(function (item, index) {
        DoSomething(connection, item, StoreResult);
        DoSomethingElse(connection, item, StoreResult);
    });
});

connection.end();

我遇到的问题(据我所知)是因为DoSomething()它似乎connection.end()在所有 ' 完成之前被调用,DoSomething()导致连接关闭时无法执行查询。

我试着在图书馆玩async,但到目前为止我还没有到任何地方。有人对如何做到这一点有一些好的建议吗?

4

2 回答 2

4

您的代码的问题是您正在同步关闭连接,同时仍在处理异步请求。connection.end()只有在调用了所有查询回调之后才应该调用。

由于您正在执行多个查询,这意味着使用某种方式来等待它们的所有结果。最简单的方法是将每个下一个调用嵌套到前一个调用的回调中,但这种方式会导致厄运金字塔。有许多流行的库可以解决这个问题,但我自己更喜欢async

使用异步我会重写你的代码如下:

async.waterfall([function(next) {
  connection.query('SELECT * FROM table WHERE deleted=?', [0], next); // note the callback
},
function(results, next) {
  // asynchronously handle each results. If they should be in order, use forEachSeries
  async.forEach(results, function(item, next) {
    // handle in parallel
    async.parallel([function(done) {
      DoSomething(connection, item, function(err, connection, item, reason) {
        // This is a hack, StoreResult should have a callback which is called
        // after it's done, because the callback is now being called too soon
        StoreResult(err, connection, item, reason);
        callback(err);
      });
    }, function(done) {
      DoSomethingElse(connection, item, function(err, connection, item, reason) {
        // This is a hack, StoreResult should have a callback which is called
        // after it's done, because the callback is now being called too soon
        StoreResult(err, connection, item, reason);
        callback(err);
    }], function(err) {
      // this callback is called with an error as soon as it occurs
      // or after all callbacks are called without error
      next(err);
    });
  }, function(err) {
    // idem
    next(err);
  });
}], function(err, results) {
  // idem
  // Do whatever you want to do with the final error here
  connection.end();
});

这还允许您解决 forEach 中查询顺序的可能问题:它们按顺序启动,但由于它们的异步性质,不能保证按顺序完成。

于 2012-12-13T11:31:17.203 回答
0

完成脚本中所需的所有操作后,关闭连接。

使用异步语言编程时,请记住脚本的真正结束点是最后一个异步回调,而不是像其他脚本(例如 PHP)那样的最后一行。

请注意,您不想简单地忽略 ,connection.end();因为底层 MySQL 驱动程序将使连接保持活动状态,并且您的脚本将永远停留在最后一行,直到您将其终止。

这是您的代码的修改版本。

connection.query('SELECT * FROM table WHERE deleted=?', [0], function (err, results) 
{
    if (err) throw err;

    results.forEach(function (item, index) {
        DoSomething(connection, item, StoreResult);
        DoSomethingElse(connection, item, StoreResult);
    });

    // End your connection here
    connection.end();
});
于 2012-12-13T11:37:29.547 回答