【问题标题】:Approach to multiple MySQL queries with Node.js使用 Node.js 处理多个 MySQL 查询的方法
【发布时间】:2011-10-01 03:40:12
【问题描述】:

我是事件/回调样式编程和 NodeJS 的新手。我正在尝试实现一个小型 http 服务器,它使用 node-mysql 模块提供 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();

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

有没有常见的方法来做到这一点?任何我不遵循的设计模式?

【问题讨论】:

    标签: javascript mysql node.js


    【解决方案1】:

    一个人应该避免厄运金字塔:

    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: promise for Javascriptwikipedia)可以使您的代码更简洁,将结果的计算和处理分开并移动。

    看看添加“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 调用的控制流的语法!
    • 我不相信这些查询会被并行执行。
    • 事实上,文档清楚地表明它们不是:“您在连接上调用的每个方法都会排队并按顺序执行。” npmjs.com/package/mysql#introduction
    • 事实上,这个解决方案显然适用于更一般的情况。实际上,它避免了厄运金字塔或通过数据共享的全球范围。
    • ES6 现在内置了promises
    【解决方案2】:

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

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

    那么,你可以只使用一个连接来执行多条语句:

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

    注意:默认情况下禁用多个语句以防止 SQL 注入。确保正确转义所有值(see docs)

    【讨论】:

      【解决方案3】:

      试着换个思路(关于异步流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);
          });
      }
      

      【讨论】:

      • 如果你有 100 个数据库查询,我想你会嵌套 100 个函数?恶心又丑陋。如果没有更好的答案,那么答案是,你不应该(而不是你不能)。
      • 如果您有 100 个查询,则说明您的数据库设计有问题
      • 不,不幸的是,要实际并行运行查询,您需要在各自的连接中运行每个查询。 mysql 协议设计的方式是您需要等待上一个命令的结果才能发送下一个命令。当您执行db.query(sql1); db.query(sql2); 时,sql2 在命令队列中,直到 sql1 完成
      • @AndreySidorov,如果您有 100 个查询,则说明您的数据库设计有问题。显然,您从未参与过大型项目。
      • @Green 我不是在说“一个项目中有 100 个不同的查询”,我说的是“100 个查询,其中每个查询都依赖于前一个查询的结果”
      【解决方案4】:

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

      取自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 数组中的下一个项目。当 items 数组为空时,我们调用 final() 函数。 (来自http://book.mixu.net/node/ch7.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-22
        • 1970-01-01
        • 2014-04-11
        • 1970-01-01
        • 2013-07-15
        • 2015-09-04
        • 1970-01-01
        • 2020-01-01
        相关资源
        最近更新 更多