在执行多个查询后终止mysql连接

kq0g1dla  于 2021-06-21  发布在  Mysql
关注(0)|答案(2)|浏览(327)

我有一些node.js代码,它在循环中从api获取数据,并运行多个mysql查询来更新一些行。
我遇到的问题是,脚本一直在运行,直到我用终止mysql连接为止 connection.end() . 我是异步代码的新手。我在哪里调用终止函数,以便在所有查询执行完毕时执行它?什么是合适的设计模式?瀑布有什么好处吗?
这是我目前拥有的代码片段(为了简单起见,删除了错误处理):

var connection = mysql.createConnection({ host, user, etc... });

for (var i = 0; i < 10; i++) {
    var url = "http://api.com?i="+i;

    request(url, function(error, response, body) {

        var data = JSON.parse(body);

        for (el in data) {
            connection.query(
                "UPDATE table SET col = ? WHERE symbol = ?",
                [
                    data[el].col,
                    el
                ]
            );
        }
    });
}

// this will run before all queries have executed
// resulting in an error
connection.end();
xxe27gdn

xxe27gdn1#

对于任何感兴趣的人,我最终通过混合承诺和计算查询来解决这个问题,类似于这样(不确定这个代码是否真的有效,但想法是存在的):

function fetchFromAPI() {
    return new Promise((resolve, reject)=>{
        var urls = [];
        for (var i = 0; i < 10; i++) {
            urls.push("http://api.com?i="+i);
        }
        var data = [];
        var requestedUrls=0;
        urls.forEach(url=>{
            request(url, (err, response, body) {
                if(err) reject(err);
                data.push(JSON.parse(body));
                requestedUrls++;
                if(requestedUrls==urls.length) resolve(data);
            };
        });
    }
}

fetchFromAPI().then(data=>{
    mysql.createConnection({ user, hostname, etc... });
    var processedKeys=0;
    data.forEach(el=> {
        mysql.query("UPDATE table SET name = ? WHERE id = ?", [el.name, el.id], (err, rows, fields) => {
            processedKeys++;
            if(processedKeys==data.length) {
                connection.end();
            }
        });
    }
}).catch(err=>{
    console.error(err);
});
8aqjt8rx

8aqjt8rx2#

所以,这里的问题是,您正在以同步的方式在这里的数据中循环:

var data = JSON.parse(body);
for (el in data) {
    connection.query(
         "UPDATE table SET col = ? WHERE symbol = ?",
         [
             data[el].col,
             el
         ]
     );
 }

mysql 模块以回调样式处理查询:

connection.query(query, function(error, rows, fields) {
    if (error) {
       return callback(error);
    } else {
       return callback(null,rows);
    }
});

哪里 callback 有签名吗 callback(error,rows) ,这样您就可以这样处理结果了,因为它应该有一个可重用的函数:

var executeQuery = function(query,callback) {
        var self=this;
        this.connection.query(query, function(error, rows, fields) {
            if (error) {
                return callback(error);
            } else {
                return callback(null,rows);
            }
        });
    }

你可以像这样调用你的代码

executeQuery(statement, function(error,rows) {
  //...
})

也就是说,您必须考虑对数据库执行多个查询,不建议在for循环中执行此操作。您应该考虑使用一个更好的解决方案,它可以是您所说的瀑布式解决方案,也可以是使用promise范式的promise解决方案。
假设有这样一个好的函数:

var promiseAllP = function(items, block) {
        var promises = [];
        items.forEach(function(item,index) {
          promises.push( function(item,i) {
              return new Promise(function(resolve, reject) {
                return block.apply(this,[item,index,resolve,reject]);
              });
            }(item,index))
        });
        return Promise.all(promises);
      }

它将一个项目数组和一个执行函数作为输入 function(item,index,resolve,reject) 有决心和拒绝承诺的功能,所以让我们把你的 executeQuery 在承诺中也起作用:

var executeQueryP = function(query) {
        var self=this;
        return new Promise(function(resolve, reject) {
           self.connection.query(query, function(error, rows, fields) {
            if (error) {
                return reject(error);
            } else {
                return resolve(null,rows);
            }
        });
    }

现在,您可以以完全异步的方式处理您的数据:

promiseAllP(data,(item,index,resolve,reject) => {
    var query= "UPDATE table SET col = %s WHERE symbol = %s";
    // example: prepare the query from item in the data
    query = replaceInString(query,item.col,item);
    executeQueryP(query)
    .then(result => resolve(result))
    .catch(error => reject(error))    
})
.then(results => { // all execution completed
 console.log(results)
})
.catch(error => { // some error occurred while executing
  console.error(error)
})

在哪里 replaceInString 会帮你准备陈述

var replaceInString = function() {
    var args = Array.prototype.slice.call(arguments);
    var rep= args.slice(1, args.length);
    var i=0;
    var output = args[0].replace(/%s|%d|%f|%@/g, function(match,idx) {
      var subst=rep.slice(i, ++i);
      return( subst );
    });
     return(output);
  },//replace,

这就是我们在这里所做的:
仅用于本地承诺
把你的mysql查询变成了一个承诺
以完全异步的方式对数据调用语句
使用了promise和promise all范式,它允许您收集promise的结果,并在所有函数完成时返回给调用者。
捕获所有语句执行中的错误
添加了一种用参数实现语句的简单方法
还要注意arrow函数语法 (param1, param2) => 这简化了编写函数的方法,对promise范式有很大帮助。

相关问题