如何在node.js mysql中使用递归而不中断连接?
我正在使用iojs和node-mysql。这是我第一次尝试异步服务器端编程。它本质上是一个批处理作业:全部运行一次,然后退出。我特别尝试在一个充满修订的表格上这样做: 过去一年编辑的每份文件;过去一年对该文件的每次修订;获取先前版本并将其内容与当前版本区分开来 因此,我使用一个查询(对于每个文档)的结果来触发任意数量的附加查询(对于每个修订版),这些查询本身必须递归(获取以前的修订版) 我不知道如何关闭数据库连接。正如我所知,递归是一个令人困惑的因素:如果我从代码中删除它,那么我就可以关闭db连接。但我需要重复 下面是一个实现我在程序中看到的行为的最小示例(假设requires和config都是确定的)如何在node.js mysql中使用递归而不中断连接?,mysql,node.js,recursion,Mysql,Node.js,Recursion,我正在使用iojs和node-mysql。这是我第一次尝试异步服务器端编程。它本质上是一个批处理作业:全部运行一次,然后退出。我特别尝试在一个充满修订的表格上这样做: 过去一年编辑的每份文件;过去一年对该文件的每次修订;获取先前版本并将其内容与当前版本区分开来 因此,我使用一个查询(对于每个文档)的结果来触发任意数量的附加查询(对于每个修订版),这些查询本身必须递归(获取以前的修订版) 我不知道如何关闭数据库连接。正如我所知,递归是一个令人困惑的因素:如果我从代码中删除它,那么我就可以关闭db连
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查询何时完成。我有一些想法 这里有一种方法(免责声明:未经测试!)不会对代码的结构进行太多更改。我使用
allquerysran
跟踪您的所有查询何时发出,并使用pendingquerys
作为计数器跟踪我们仍在等待的查询数量
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;
}
});
}
如果您愿意进入兔子洞,promise库也可以使您的代码简洁。我喜欢。例如,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();
});
请注意,这其中一个方便的特性是,如果查询返回一个
错误,那么对延迟.reject()
的调用将使您的执行流程短接到最底层的.fail()
处理程序。我喜欢这个答案,非常干净:)。drain
函数是否具有错误参数?或者队列是否触发错误事件?不,错误发生时必须正确处理,您可以选择允许队列继续、暂停、终止等。我不认为有任何关于错误处理的假设。