2015-05-01 50 views
3

我正在使用iojs和node-mysql。这是我第一次进入异步服务器端编程。它基本上是一个批处理作业:运行一次,退出。我特意试图在一张充满版本的表格上做到这一点:如何在不断开连接的情况下在node.js mysql中使用递归?

对于过去一年中编辑的每个文档;该文件在过去一年中的每次修订;获得之前的修订并将其内容与当前版本进行比较。

所以,我用一个查询(每个文档)的结果,以火过的其他查询任意数量(每个修订),必须自己递归(获得前修订) 。

我想不出如何关闭数据库连接。据我所知,递归是混杂因素:如果我从代码中删除它,那么我可以关闭数据库连接。但我需要缓解。

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

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

我已经很努力在累加器注册数据库查询和每个查询结束递减蓄电池来解决问题,但是这并没有产生可预测的成功,但它使代码的痛苦与合作。

回答

3

我喜欢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(); 
}; 
+0

我喜欢这个答案,很干净:)。 'drain'函数是否带有err参数?或者排队激发错误事件? –

+1

不,错误必须在发生时适当地处理,您可以选择允许队列继续,暂停,终止等等。我不认为有任何关于错误处理的假设。 https://github.com/caolan/async/blob/master/lib/async。js#L731 –

1

调试,我认为当你所有的异步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()处理程序的执行流程最底部。

+0

非常感谢 - 当我要使用Peter Lyons解决方案时,您的回答帮助我了解了更多关于Node.js中的编程的内容。非常感谢! – hoosteeno

相关问题