【问题标题】:How do i format mysql query to utilize async/promsies?如何格式化 mysql 查询以利用异步/承诺?
【发布时间】:2017-11-12 17:12:32
【问题描述】:

我正在尝试使用 2 个参数对我的数据库进行简单查询,但在尝试使用 Promises/Async 重新格式化此代码以避免回调地狱时遇到了麻烦。代码如下:

module.exports = {
  getDailyRaw: function(school, meal, callback) {
     var sql = "SELECT * FROM daily WHERE school = ? AND meal = ?";
     pool.getConnection(function(err, conn) {
         if(err) { console.log(err); callback(true); return; }
         conn.query(sql, [school, meal], function(err, results) {
             conn.release();
             if(err) { console.log(err); callback(true); return; }
             callback(false, school, results);
         })
     })
  }, ....

我一直在尝试查找有关解决此问题的教程,但无法正确实施/理解它们。

编辑:我现在正在使用“promise-mysql”库来完成工作,但我仍然无法将多个查询链接在一起。我如何将已经建立的连接传递给另一个 then 语句,以便我可以再次调用查询? 更新代码:

getDaily: function(school, meal, callback) {
    pool.getConnection().then(function(conn) {
        var sql = "SELECT * FROM daily WHERE school = ? AND meal = ?";
        return conn.query(sql, [school,meal]);
    }).then(function(rows) {
        var qMarks = "";
        var foodNames = [school];
        rows.forEach(function(item) {
            foodNames.push(item.name);
            qMarks += "?,";
        });
        qMarks = qMarks.substring(0, qMarks.length - 1);
        var sql = "SELECT * FROM foods WHERE school = ? AND name IN (" + qMarks + ")";
        return conn.query(sql, foodNames);
    }).then(function(finalData) {
        callback(finalData);
    }).catch(function(err) {
        callback(null);
        console.log(err);
    })
},

【问题讨论】:

  • 您在 node.js 中使用了哪个确切的 mysql 模块?是node-mysql吗?
  • 包名看起来只是'mysql',但我不确定它是否与node-mysql相同。
  • 或许可以使用promise-mysql:npmjs.com/package/promise-mysql
  • 感谢您的建议!但是,请参阅更新的代码以了解出现的新问题。

标签: mysql node.js asynchronous callback promise


【解决方案1】:

您可以通过同步执行器nsynjs 以顺序方式编写和执行您的逻辑。它逐步运行代码,自动暂停承诺并等待它们的解决,然后再进行下一步。代码将如下所示:

function synchronousCode(pool, school, meal){
    var conn = pool.getConnection().data;
    var sql = "SELECT * FROM daily WHERE school = ? AND meal = ?";
    var rows = conn.query(sql, [school,meal]).data;
    // rows from 'daily' table are ready at this point
    var qMarks = "";
    var foodNames = [school];
    for(var i=0; i<rows.length; i++) {
        foodNames.push(rows[i].name);
        qMarks += "?,";
    };
    qMarks = qMarks.substring(0, qMarks.length - 1);
    sql = "SELECT * FROM foods WHERE school = ? AND name IN (" + qMarks + ")";
    var foods = conn.query(sql, foodNames).data;
    // rows from 'foods' table are ready at this point
    ... process food, or ...
    return foods;
};

var nsynjs = require('nsynjs');
var school =..., meal = ..., pool = ...;
nsynjs.run(synchronousCode,{},pool, school, meal,function(foods){
    console.log('synchronousCodeis done',foods);
});

【讨论】:

    【解决方案2】:

    有多种方法可以使来自一个链式.then() 的变量在链中的某个位置可用。您可以在How to Chain and Share Prior Results with Promises 中查看这些选项的摘要。

    对于这种特殊情况,我建议像这样进行一层嵌套:

    getDaily: function(school, meal, callback) {
        pool.getConnection().then(function(conn) {
            var sql = "SELECT * FROM daily WHERE school = ? AND meal = ?";
            return conn.query(sql, [school,meal]).then(function(rows) {
                var qMarks = "";
                var foodNames = [school];
                rows.forEach(function(item) {
                    foodNames.push(item.name);
                    qMarks += "?,";
                });
                qMarks = qMarks.substring(0, qMarks.length - 1);
                var sql = "SELECT * FROM foods WHERE school = ? AND name IN (" + qMarks + ")";
                return conn.query(sql, foodNames);
            }).then(function(finalData) {
                callback(finalData);
            });
        }).catch(function(err) {
                callback(null);
                console.log(err);
        });
    },
    

    而且,最好完全摆脱回调,只返回承诺并让调用者使用承诺。然后,如果调用者想要与其他人同步这个异步操作,它已经使用了一个承诺让他们更容易:

    getDaily: function(school, meal) {
        return pool.getConnection().then(function(conn) {
            var sql = "SELECT * FROM daily WHERE school = ? AND meal = ?";
            return conn.query(sql, [school,meal]).then(function(rows) {
                var qMarks = "";
                var foodNames = [school];
                rows.forEach(function(item) {
                    foodNames.push(item.name);
                    qMarks += "?,";
                });
                qMarks = qMarks.substring(0, qMarks.length - 1);
                var sql = "SELECT * FROM foods WHERE school = ? AND name IN (" + qMarks + ")";
                return conn.query(sql, foodNames);
            });
        }).catch(function(err) {
            console.log(err);
            throw err;
        });
    },
    

    注意:如果您要返回 promise 并希望在 .catch() 中记录错误,则必须重新抛出错误以确保返回的 promise 仍然被拒绝(就像 try/catch 一样)。

    【讨论】:

    • 非常感谢!这看起来很棒。但是,当在我的 index.js 路由文件中使用此承诺时,我是否将 .then 附加到函数调用 getDaily 以继续该链?当我尝试这样做时,它说无法读取未定义的属性'then',而不是让我能够链接它。我该如何解决这个问题?
    • 没关系,我忘了把 return 放在最上面,这样它就会返回 promise 本身。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-17
    • 2019-12-04
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多