【问题标题】:NodeJs MySql multiple updateNodeJs MySql 多次更新
【发布时间】:2019-02-17 06:10:52
【问题描述】:

我在 NodeJs 中有一个使用 Express 框架的方法,我在其中 迭代数组并在 Mysql DB 中进行更新
代码接收一个 Connection 对象和一个 Post Body,
Post Request Body 是一个对象数组,包含要保存在 DB 中的数据,
我正在尝试逐个循环对象并使用更新查询将它们保存在数据库中

现在奇怪的是,代码只有在立即被调用两次时才有效
IE。在测试中我发现,我必须发出两次 API 请求才能让代码保存数据。

我在第一次 API 调用时收到以下错误 -

Error Code: 1205. Lock wait timeout exceeded; try restarting transaction

这是一个简单的Update调用,我检查了MySql进程,没有死锁,

SHOW FULL PROCESSLIST;

但相同的代码在第二次 API 调用中起作用。

let updateByDonationId = async (conn, requestBody, callback) => {

    let donations = [];
    donations = requestBody.donations;

    //for(let i in donations){
    async.each(donations, function(singleDonation, callback) {
        //let params = donations[i];
        let params = singleDonation;

        let sqlData = []
        let columns = "";

        if(params.current_location != null){
            sqlData.push(params.current_location);
            columns += "`current_location` = ?,";
        }
        if(params.destination_location != null){
            sqlData.push(params.destination_location);
            columns += "`destination_location` = ?,";
        }

        if(columns != ''){
            columns = columns.substring(0,columns.length-1);

            let sqlQuery = 'UPDATE donation_data SET '+columns
            +' WHERE donation_id = "' + params.donation_id + '"';

            conn.query(sqlQuery, sqlData, function (err, result) {
                logger.info(METHOD_TAG, this.sql);
                if (err) {
                    logger.error(METHOD_TAG, err);
                    return callback(err, false);
                }
            })
        }
        else{
            return callback(null, false);
        }
        columns = "";
        sqlData = [];
    },
    function(err, results) {
        if (err) {
            logger.error(METHOD_TAG, err);
            return callback(err, false);
        }
        else{
           return callback(null, true);
        }
    });
    //return callback(null, true);

} // END

还提到以下内容,我猜他也因为奇怪的原因得到了 ER_LOCK_WAIT_TIMEOUT -
NodeJS + mysql: using connection pool leads to deadlock tables


问题似乎与正确指出的 Node 的非阻塞异步性质有关
谁能提供正确的代码?

【问题讨论】:

    标签: mysql node.js


    【解决方案1】:

    我想说 Node.js 的异步特性会在这里给您带来问题。您可以尝试重写循环。您可以使用 Promise 或 async.eachSeries 方法。

    尝试更改循环以使用以下内容:

            async.eachSeries(donations, function(singleDonation, callback) { 
    

    【讨论】:

    • 我已经按照你的建议更新了代码,你能交叉检查一下吗?但是这次我调用API,API没有得到响应,甚至没有错误,可能是我的代码问题,请帮忙检查。
    • 代码是否执行?你可以在循环内设置断点吗?这将与未调用的回调函数有关。
    • 是的代码运行,调试器也被捕获在查询结果块中并显示 1 个受影响的行,但代码没有进入最终函数,我返回的回调错误吗?
    • 如果捐赠数组中有多个值,那么看起来 conn.query 的返回中的回调可能会让您退出循环。
    • 是的,捐赠是一个数组,我们应该如何正确地执行这个数组?
    【解决方案2】:

    .query() 该方法是异步的,因此您的代码会尝试一个接一个地执行查询,而无需等待前者完成。在数据库方面,如果它们碰巧影响到数据库的同一部分,它们就会排队,即,一个查询在数据库的该部分上有一个“锁定”。现在其中一个事务必须等待另一个事务完成,如果等待时间超过阈值,则会导致您得到的错误。

    但是您说您在第二次立即调用时没有收到错误,我的猜测是在第一次调用期间数据被缓存,因此第二次调用更快并且足够快以保持等待阈值因此错误不是在第二次调用时引起的。

    为了避免这一切并仍然保持代码的异步特性,您可以使用 Promiseasync-await

    第一步是为我们的.query() 函数创建一个基于 Promise 的包装函数,如下所示:

    let qPromise = async (conn, q, qData) => new Promise((resolve, reject) => {
        conn.query(q, qData, function (err, result) {
            if (err) {
                reject(err);
                return;
            }
            resolve(result);
        });
    });
    

    现在这是你修改后的函数,它使用了这个基于 Promise 的函数和 async-await:

    let updateByDonationId = async (conn, requestBody, callback) => {
        let donations = [];
        donations = requestBody.donations;
        try {
            for (let i in donations) {
                let params = donations[i];
                let sqlData = [];
                let columns = "";
    
                if (params.current_location != null) {
                    sqlData.push(params.current_location);
                    columns += "`current_location` = ?,";
                }
                if (params.destination_location != null) {
                    sqlData.push(params.destination_location);
                    columns += "`destination_location` = ?,";
                }
    
                if (columns != '') {
                    columns = columns.substring(0, columns.length - 1);
    
                    let sqlQuery = 'UPDATE donation_data SET ' + columns
                        + ' WHERE donation_id = "' + params.donation_id + '"';
    
                    let result = await qPromise(conn, sqlQuery, sqlData);
                    logger.info(METHOD_TAG, result); // logging result, you might wanna modify this
    
                }
                else {
                    return callback(null, false);
                }
                columns = "";
                sqlData = [];
            }
        } catch (e) {
            logger.error(METHOD_TAG, e);
            return callback(err, false);
        }
        return callback(null, true);
    }
    

    我是即时编写代码的,所以可能存在一些语法错误。

    【讨论】:

    • 出现错误 - let result = await qPromise(conn, sqlQuery, sqlData); ^^^^^^^^ SyntaxError: Unexpected identifier
    • @AniruddhaRaje 确保 updateByDonationId() 是一个异步函数,即在其定义/原型行中有关键字 async,如下所示:let updateByDonationId = async (conn, requestBody, callback) => {
    • @AniruddhaRaje 尝试从网上运行简单的 async-await 示例,如果遇到同样的错误,则需要更新 nodejs 版本。
    猜你喜欢
    • 2015-07-12
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 2014-10-22
    • 2020-10-25
    • 2016-01-13
    • 2019-08-21
    相关资源
    最近更新 更多