Nodejs没有在ForLoop中等待mysql响应



我有一个条件,我需要检查值是否存在于mysql中,如果值存在,那么我们需要更新,如果不存在,那么我们需要插入。这里我使用了这个条件但由于异步任务nodejs不等待响应当响应来的时候它不检查它只是插入数据,请查看


db_connection.js
check_by_column(tablename, selectedKeys, values, selectedValues, callback) {
const show_key = [];
for (const [key, value] of Object.entries(values)) {
show_key.push(key+" = "+"'"+value+"'");
}
const column = show_key.join(" ");
var sql = "SELECT "+ selectedKeys +" FROM "+ tablename +" WHERE "+ column;
console.log(sql)
con.query(sql, function (err, result) {
if (err) {
console.log("database Error")
callback(err);
// throw err
} else {
if (result && result.length == 0 ) {
callback(5);
} else {
callback(3);
}
}
return;
})
}
insert_value(tablename, values, callback) {
const show_key = [];
const show_Values = [];
for (const [key, value] of Object.entries(values)) {
show_key.push(key);
show_Values.push(value);
}
const nKey = show_key.join(", ");
const nValue = show_Values.join("', '");
let sql = "INSERT INTO "+ tablename +" ("+ nKey +") VALUES ('"+ nValue +"')";
con.query(sql, function (err, result) {
if (err) {
console.log("database Error")
console.log(err);
throw err;
}
// console.log("1 record inserted");
callback(result);
});
}
index.js
var dat = {"IMEI": 80, "rule": 2, "id": 1, "operation": 4, "address": 48, "qty": 6, "delay": 10, "data" : "3231,3039,3339", "error" : 0, "Timestamp":"2021-10-12 11:41:22"};
const topicData = JSON.stringify(dat);
var query = JSON.parse(topicData);
const currentDateTime = moment().format("YYYY-MM-DD HH:mm:ss");
const groups = [1, 2];
for (let i = 0; i < groups.length; i++) {
console.log(i)
db.check_by_column('ml', 'number', { "number": query.data }, {"topic":"80", "IMEI":query.IMEI, "id":query.id, "number": query.data, "start_date":currentDateTime, "end_date": currentDateTime}, function (response) {
if (response === 5) {
db.insert_value('ml', {"topic":"80", "IMEI":query.IMEI, "id":query.id, "number": query.data, "start_date":currentDateTime, "end_date": currentDateTime}, function(response) {
console.log("insert")
});
} else {
db.update_by_column('ml', {"topic":"80", "IMEI":query.IMEI, "id":query.id, "number": query.data, "start_date":currentDateTime, "end_date": currentDateTime}, {"number":query.data}, function(response) {
console.log("update")
});
}
});
}

反应

0
SELECT number FROM ml WHERE number = '3231,3039,3339'
1
SELECT number FROM ml WHERE number = '3231,3039,3339'
insert
insert

您的db调用是异步和非阻塞的。这意味着它们在调用它们之后立即返回,之后的代码继续执行(例如for循环的其余部分),然后在整个for循环完成后,在一些不确定的时间之后调用完成回调。

因此,像for循环中的这些异步操作最终是并行运行的,而不是顺序运行的。按顺序运行它们(使for循环在推进for循环之前等待异步操作完成)的最简单方法是使用asyncawait。这就要求修改异步操作,以返回一个解析或拒绝的承诺,而不是使用回调。让我们一步一步来看看。首先,我们修改check_by_column()以返回这样一个承诺:

check_by_column(tablename, selectedKeys, values, selectedValues) {
return new Promise((resolve, reject) => {
const show_key = [];
for (const [key, value] of Object.entries(values)) {
show_key.push(key + " = " + "'" + value + "'");
}
const column = show_key.join(" ");
var sql = "SELECT " + selectedKeys + " FROM " + tablename + " WHERE " + column;
console.log(sql)
con.query(sql, function(err, result) {
if (err) {
console.log("database Error")
reject(err);
} else {
if (result && result.length == 0) {
resolve(5);
} else {
resolve(3);
}
}
})
});
}

这是通过手动将异步操作包装在承诺中并捕获它可以完成的所有方式(包括错误和结果)并将它们挂钩到承诺来完成的。注意:如果你切换到msql2版本的库,它有内置的承诺支持,这个手动包装器将不需要,因为你可以使用内置的承诺支持。但是,为了便于解释,我将展示如何手动构造承诺。

,你对insert_value()做类似的事情:

insert_value(tablename, values, callback) {
return new Promise((resolve, reject) => {
const show_key = [];
const show_Values = [];
for (const [key, value] of Object.entries(values)) {
show_key.push(key);
show_Values.push(value);
}
const nKey = show_key.join(", ");
const nValue = show_Values.join("', '");
let sql = "INSERT INTO " + tablename + " (" + nKey + ") VALUES ('" + nValue + "')";
con.query(sql, function(err, result) {
if (err) {
console.log("database Error")
console.log(err);
reject(err);
return;
}
// console.log("1 record inserted");
resolve(result);
});
});
}

现在,这两个函数都是使用承诺来表达的,我们可以使用asyncawait来重组for循环,这样它实际上会为每个数据库操作暂停for循环的执行,从而按顺序运行数据库操作,而不是并行运行:

async function checkAndUpdate() {
var dat = {"IMEI": 80, "rule": 2, "id": 1, "operation": 4, "address": 48, "qty": 6, "delay": 10, "data" : "3231,3039,3339", "error" : 0, "Timestamp":"2021-10-12 11:41:22"};
const topicData = JSON.stringify(dat);
var query = JSON.parse(topicData);
const currentDateTime = moment().format("YYYY-MM-DD HH:mm:ss");
const groups = [1, 2];
for (let i = 0; i < groups.length; i++) {
console.log(i)
let response = await db.check_by_column('ml', 'number', { "number": query.data }, {"topic":"80", "IMEI":query.IMEI, "id":query.id, "number": query.data, "start_date":currentDateTime, "end_date": currentDateTime});
if (response === 5) {
let insertResult = await db.insert_value('ml', {"topic":"80", "IMEI":query.IMEI, "id":query.id, "number": query.data, "start_date":currentDateTime, "end_date": currentDateTime});
console.log("inserted")
} else {
let insertResult = await db.update_by_column('ml', {"topic":"80", "IMEI":query.IMEI, "id":query.id, "number": query.data, "start_date":currentDateTime, "end_date": currentDateTime}, {"number":query.data});
console.log("updated")
}
}
}
checkAndUpdate().then(result => {
console.log("all done");
}).catch(err => {
console.log(err);
});

另一个注释,这段代码看起来可能会受到竞争条件的影响,因为如果一些其他代码甚至另一个运行相同代码的请求也试图插入这个值,它可能会与这段代码发生冲突,因为你正在检查一个值,然后根据它是否已经存在改变你的行为。我不太了解你的数据库,但通常会有一个原子操作,根据值是否已经存在来插入或更新,你可以让数据库自动完成。

最新更新