使用 Node.js 同步数据库查询
我有一个 Node.js/Express 应用程序,它查询路由中的 MySQL 数据库并向用户显示结果。我的问题是如何运行查询并阻止直到两个查询都完成后再将用户重定向到他们请求的页面?
在我的示例中,我有 2 个查询需要在渲染页面之前完成。如果我将查询 2 嵌套在查询 1 的“结果”回调中,我可以让查询同步运行。但是,当查询数量增加时,这将变得非常复杂。
如何同步运行多个(在本例中为 2 个)数据库查询,而不将后续查询嵌套在前一个查询的“结果”回调中?
我查看了 Node 模块中的“流程控制/异步好东西”并尝试了 flow-js,但我无法让它与异步查询一起使用。
下面列出了我尝试从“/home”路由执行的 2 个查询。节点专家能否解释执行此操作的“正确”方法?
app.get('/home', function (req,res) {
var user_array = [];
var title_array = [];
// first query
var sql = 'select user_name from users';
db.execute(sql)
.addListener('row', function(r) {
user_array.push( { user_name: r.user_name } );
})
.addListener('result', function(r) {
req.session.user_array = user_array;
});
// second query
var sql = 'select title from code_samples';
db.execute(sql)
.addListener('row', function(r) {
title_array.push( { title: r.title } );
})
.addListener('result', function(r) {
req.session.title_array = title_array;
});
// because the queries are async no data is returned to the user
res.render('home.ejs', {layout: false, locals: { user_name: user_array, title: title_array }});
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
节点的目标不是关心事情发生的顺序。这可能会使某些场景变得复杂。嵌套回调并不可耻。一旦你习惯了它的外观,你可能会发现你实际上更喜欢这种风格。我愿意;非常清楚将触发什么订单回调。如果有必要,您可以放弃匿名函数以使其不那么冗长。
如果您愿意稍微重构一下代码,则可以使用“典型”嵌套回调方法。如果您想避免回调,有许多异步框架可以尝试帮助您做到这一点。您可能想要查看的一个是 async.js (https://github.com/fjakobs/async.js)。每个示例:
对于一次性,我可能只使用引用计数类型的方法。只需跟踪您想要执行的查询数量,并在它们全部完成后呈现响应即可。
更好的方法是在渲染响应之前在每个“结果”回调中简单地调用 finishRequest() 来检查非空数组。这是否适合您的情况取决于您的要求。
The goal with node is not to care what order things happen in. This can complicate some scenarios. There is no shame in nesting callbacks. Once you are used to how it looks, you may find that you actually prefer that style. I do; it is very clear what order callbacks will fire. You can forgo the anonymous functions to make it less verbose if you have to.
If you are willing to restructure your code a bit, you can use the "typical" nested callback method. If you want to avoid callbacks, there are numerous async frameworks that will try and help you do this. One that you might want to check out is async.js (https://github.com/fjakobs/async.js). Example of each:
For a one-off, I would probably just use a reference counting type approach. Simply keep track of how many queries you want to execute and render the response when they have all finished.
An even nicer approach would be to simply call finishRequest() in each 'result' callback an check for non-empty arrays before you render the response. Whether that will work in your case depends on your requirements.
这是处理多个回调的一个非常简单的技巧。
示例
用法:
所以基本上你需要引用计数。这是这些情况下的标准方法。我实际上使用这个小实用函数而不是流量控制。
如果您想要一个完整的流量控制解决方案,我会推荐 futuresJS
Here's a really easy trick to handle multiple callbacks.
Example
Usage:
So basically you need reference counting. This is the standard approach in these situations. I actually use this small utility function instead of flow control.
If you want a full blown flow control solution I would recommend futuresJS
我发现异步库最适合此类事情。 https://github.com/caolan/async#parallel
我无法测试这个或任何东西,所以如果有一些错别字请原谅。我重构了您的查询函数以使其可重用。因此,调用 queryRows 将返回一个与异步模块并行回调函数的格式匹配的函数。两个查询完成后,它将调用最后一个函数并将两个查询的结果作为参数传递,您可以读取该结果并将其传递给模板。
I find that the async library is the best for things like this. https://github.com/caolan/async#parallel
I can't test this or anything, so forgive me if there are some typos. I refactored your query function to be reusable. So, calling queryRows will return a function that matches the format of the async module's parallel callback functions. After both queries are complete, it will call the last function and pass the result of the two queries as an argument, which you can read to pass to your template.
这里有一些解决方案,但在我看来,最好的解决方案是以一种非常简单的方式使代码同步。
您可以使用“synchonize”包。
只是
然后
varsync = require(synchronize);
使用
sync. Fiber(function() { 将需要同步的逻辑放入 Fiber 中
//把你的逻辑放在这里
}
两个 mysql 查询的示例:
当调用“saveSomething()”时,它会在主表中插入一行并接收最后插入的 id。之后将执行下面的代码。不需要嵌套的承诺或类似的东西。
There are some solutions here, but in my opinion the best solution is to make the code synchronously in a very easy way.
You could use the "synchonize" package.
Just
Then
var sync = require(synchronize);
Put logic which should be synchronous into a fiber by using
sync.fiber(function() {
//put your logic here
}
An example for two mysql queries:
When "saveSomething()" is called, it inserts a row in a main table and receives the last inserted id. After that the code below will be executed. No need for nesting promises or stuff like that.
选项一:如果所有查询都相互关联,则创建存储过程,将所有数据逻辑放入其中,并使用单个
db.execute
选项二:如果您的数据库使用一个连接,则命令一个有保证的连接串行执行,您可以将其用作异步助手
option one: if all your queries related to each other, create stored procedure, put all your data logic into it and have a single
db.execute
option two: if your db uses one connection then commands a guaranteed to be executed serially and you can use this as async helper
您可以使用 Fiber 与 Node.JS 编写伪同步代码,看看这些 DB 测试 http://alexeypetrushin.github.com/synchronize
You can use fibers to write pseudo-synchronous code with Node.JS take a look at these tests for DB https://github.com/alexeypetrushin/mongo-lite/blob/master/test/collection.coffee
they are asynchronous but looks like synchronous, more details http://alexeypetrushin.github.com/synchronize