NodeJs MySql多次更新
我在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的非阻塞异步性质有关 任何人都可以帮助正确的代码吗?
回答如下:.query()
该方法是异步的,因此您的代码尝试执行一个接一个的查询而不等待前者完成。在数据库方面,如果它们恰好影响它的相同部分,它们就会排队等待,即一个查询在数据库的该部分上有一个“锁定”。现在其中一个事务必须等待另一个事务完成,如果等待时间超过阈值,则会导致您获得的错误。
但你说你没有在第二个立即调用时得到错误,我的猜测是在第一次调用期间数据被缓存,因此第二次调用更快,并且它足够快以使等待低于阈值因此错误不是在第二次调用时引起的。
为了避免这一切,仍然保持代码的异步性质,你可以使用Promise和async-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);
}
我在飞行中编写代码,因此可能存在一些语法错误。