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 を使用して、次のようにコードを書き直します。

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 に答える