使用 Node.js 处理多个 MySQL 查询的方法

IT技术 javascript mysql node.js
2021-03-03 18:01:45

我是事件/回调风格编程和 NodeJS 的新手。我正在尝试实现一个小的 http 服务器,它使用 node-mysql module提供 ddbb 数据。

我的问题来自查询结构。由于经常有查询需要运行先前查询的结果,因此我无法同时(异步)运行所有这些查询,我不得不等待一些结果。

我的第一种方法是同时运行所有非依赖查询,然后循环,直到所有查询都设置了一个标志,说我已经完成,这样我就可以继续使用依赖(同步)查询,但我没有知道这是否是正确的方法。

像这样的东西:

function x(){
    var result_for_asynch_query_1 = null
    var result_for_asynch_query_2 = null

    mainLoop(){
        // call non-dependant query 1
        // call non-dependant query 2

        // loop until vars are != null

        // continue with queries that require data from the first ones
    }
}

//for each browser request
httpServer{
     call_to_x();
}.listen();

这样我可以在最终结果中节省一些时间,因为我不会以串行方式等待所有响应,而是等待最长的响应。

有没有一种通用的方法来做到这一点?我没有遵循任何设计模式?

4个回答

人们应该避免厄运金字塔:

var express = require('express');
var Q = require('Q');
var app = express();

app.get('/',function(req,res){
    var mysql      = require('mysql');

    var connection = mysql.createConnection({
        host     : 'localhost',
        user     : 'root',
        password : ''
    });

    connection.connect();

    function doQuery1(){
        var defered = Q.defer();
        connection.query('SELECT 1 AS solution',defered.makeNodeResolver());
        return defered.promise;
    }

    function doQuery2(){
        var defered = Q.defer();
        connection.query('SELECT 2 AS solution',defered.makeNodeResolver());
        return defered.promise;
    }

    Q.all([doQuery1(),doQuery2()]).then(function(results){
        res.send(JSON.stringify(results[0][0][0].solution+results[1][0][0].solution));
        // Hint : your third query would go here
    });

    connection.end();

});

app.listen(80);
console.log('Listening on port 80');

此示例显示了取决于 2 个独立计算值的结果。在 doQuery1 和 doQuery2 中查询这些值中的每一个。它们按顺序执行,但异步执行。

接下来你可以看到Q.all(...它基本上在成功时调用“then”回调。在该回调中,计算完成。

使用Promise(详细信息:Github Q:Javascript维基百科的Promise)允许使您的代码更清晰,将结果的计算和处理分开并移动周围的东西。

看看添加“doQuery3”作为计算的先决条件是多么容易!

然后是属于示例代码的“package.json”:

{
    "name": "hello-world",
    "description": "hello world test app",
    "version": "0.0.1",
    "private": true,
    "dependencies": {
        "express": "3.2.0",
        "q": "0.9.3",
        "mysql":"2.0.0-alpha7"
    }
}
谢谢,我一生都无法弄清楚处理多个 mysql nodejs 调用的控制流的语法!
2021-05-03 18:01:45
我不相信这些查询会并行执行。
2021-05-05 18:01:45
ES6promise现在已经内置了
2021-05-15 18:01:45
事实上,这个解决方案显然适用于更通用的情况。事实上,它避免了厄运金字塔或通过数据共享的全球化范围。
2021-05-18 18:01:45
事实上,文档清楚地表明它们不是:“您在连接上调用的每个方法都在排队并按顺序执行。” npmjs.com/package/mysql#introduction
2021-05-20 18:01:45

另一种解决方案是连接所有语句,每个语句以分号结尾。例如,要从多个表中进行选择,您可以使用以下查询:

var sql = 'select * from user; select * from admin;'

然后,您可以只使用一个连接来执行多条语句:

var connection = mysql.createConnection({multipleStatements: true}) connection.query(sql)

注意:默认情况下禁用多条语句以防止 SQL 注入。确保正确转义所有值(参见文档)

尝试以其他方式思考(异步流howtonode.org上有很好的介绍

var db = get_link_or_pool();

do_queries( callback ) {
    db.query(sql1, function(err, res1) {
        if (err) {
             callback(err);
             return;
        }
        // use res1 ...
        db.query(sql2, function(err, res2) {
             if (err) {
                 callback(err);
                 return;
             }
             callback(null, res2); // think 'return'
        }
    });
}

request_handler(req) {
    do_queries( function(err, result) {
        if(err)
            report_error(err);
        else
            write_result(req, result);
    });
}
@Green 我不是在谈论“一个项目中有 100 个不同的查询”,而是在谈论“100 个查询,其中每个查询都取决于前一个查询的结果”
2021-05-04 18:01:45
@AndreySidorov,如果您有 100 个查询那么您的数据库设计就有问题显然,您从未参与过大型项目。
2021-05-08 18:01:45
不,不幸的是,要实际并行运行查询,您需要在自己的连接中运行每个查询。mysql 协议的设计方式是您需要等待上一个命令的结果,然后才能发送下一个命令。当你做db.query(sql1); db.query(sql2);sql2 时,在命令队列中,直到 sql1 完成
2021-05-15 18:01:45
如果你有 100 个 db 查询,我想你会嵌套 100 个函数?像地狱一样令人讨厌和丑陋。如果没有更好的答案,那么答案是,你不应该(而不是你不能)。
2021-05-17 18:01:45
如果您有 100 个查询,那么您的数据库设计就有问题
2021-05-17 18:01:45

我发现以下内容对解决此问题非常有帮助:

取自http://book.mixu.net/node/ch7.html - 这里有很多其他很棒的例子!!

function async(arg, callback) {
  console.log('do something with \''+arg+'\', return 1 sec later');
  //replace setTimeout with database query  
  setTimeout(function() { callback(arg * 2); }, 1000);
}
// Final task (return data / perform further operations)
function final() { console.log('Done', results); }

// A simple async series:
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
function series(item) {
  if(item) {
    async( item, function(result) {
      results.push(result);
      return series(items.shift());
    });
  } else {
    return final();
  }
}
series(items.shift());

"取一组项目,用第一个项目调用系列控制流函数。系列启动一个 async() 操作,并传递一个回调给它。回调将结果推送到结果数组中,然后用下一个调用系列items 数组中的 item。当 items 数组为空时,我们调用 final() 函数。” (来自http://book.mixu.net/node/ch7.html