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

时间:2018-01-06 19:58:44

标签: javascript mysql node.js asynchronous

我有一些node.js代码,它从循环中的API获取数据并运行mutliple mysql查询来更新某些行。

我遇到的问题是脚本一直运行,直到我终止与connection.end()的mysql连接。我是异步代码的新手。我在哪里调用终止函数,以便在所有查询完成执行后执行?什么是正确的设计模式? waterfall会有什么好处吗?

这是我目前的代码片段(为简单起见,删除了错误处理):

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(); 

2 个答案:

答案 0 :(得分:1)

所以,这里的问题是你通过这里的数据同步循环:

writeln/1

write/1模块以回调样式处理查询:

nl

其中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

也就是说,您必须考虑对数据库进行多次查询,并且不建议在for循环中执行此操作。你应该考虑使用一个更好的解决方案,就像你说的那样,或者使用Promise范例的承诺。

假设有这个好的功能:

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); } }); } 作为输入,该函数具有Promise的解析和拒绝功能,所以让我们将你的executeQuery(statement, function(error,rows) { //... }) 函数转换为Promise:< / p>

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);
            }
        });
    }

这就是我们在这里所做的:

  • 仅使用原生承诺
  • 在承诺
  • 中转换了您的mysql查询
  • 以完全异步的方式针对您的数据调用语句
  • 使用Promise并承诺所有范例,让你收集Promise的结果并在完成所有功能后返回给调用者。
  • 执行所有语句中的错误
  • 添加了一种简单的方法来实现带参数的语句

另请注意箭头函数语法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) }) ,它简化了编写函数的方式,这对Promise范例有很大帮助。

答案 1 :(得分:0)

对于任何有兴趣的人,我最终通过混合的承诺和计算查询来解决它,这与此类似(不确定这段代码是否真的有效,但想法就在那里):

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);
});