繁体   English   中英

如何在不破坏连接的情况下在node.js mysql中使用递归?

[英]How to use recursion in node.js mysql without breaking connection?

我正在使用iojs和node-mysql。 这是我第一次涉足异步服务器端编程。 它本质上是一个批处理作业:运行一次,退出。 我特意尝试在充满修订的表格上执行此操作:

对于过去一年编辑的每份文件; 对于过去一年中对该文件的每次修订; 获得先前的修订版并将其内容与当前版本区分开来。

因此,我使用一个查询( 对于每个文档 )的结果来触发必须自己递归的任意数量的附加查询( 对于每个修订 )( 获得先前的修订 )。

我无法弄清楚如何关闭数据库连接。 接近我可以说,递归是混淆因素:如果我从代码中删除它,那么我可以关闭数据库连接。 但我需要递归。

这是一个最小的例子(假设需求和配置都没问题),它完成了我在程序中看到的行为。

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);
        }
    });
}

我已经非常努力地通过在累加器中注册数据库查询并在每个查询结束时递减累加器来解决问题,但是这还没有产生可预测的成功,并且使代码难以使用。

我喜欢这种工作负载的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();
};

我认为您的问题是检测所有异步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()处理程序。

暂无
暂无

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

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