NodeJs MySql多次更新

时间:2019-02-17 06:10:53

标签: mysql node.js

我在NodeJs中有一种使用Express框架的方法,其中迭代数组并在Mysql DB中进行更新
该代码接收一个Connection对象和一个Post Body,
发布请求正文是对象的数组,包含要保存在数据库中的数据,
试图一个接一个地循环对象,并使用更新查询将其保存在数据库中。

现在奇怪的是,该代码仅在立即被调用两次时才有效
就是在测试中,我发现我必须两次请求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的非阻塞异步性质有关
任何人都可以提供正确的代码吗?

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

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

我是动态编写代码的,因此可能存在一些语法错误。