gpt4 book ai didi

node.js - Node -mysql事务在唯一键违规后不会回滚

转载 作者:太空宇宙 更新时间:2023-11-03 21:55:22 29 4
gpt4 key购买 nike

我正在我的应用程序中测试 Node mysql 事务,方法是在第一次执行 UPDATE 后执行会违反 UNIQUE 键约束的 INSERT。虽然 INSERT 失败,但我发现初始 UPDATE 成功,尽管事务带有 ROLLBACK。 MySQL UPDATE 不会执行隐式提交,因此我不确定这里到底发生了什么。

pool.getConnection(function (err, connection) {

connection.beginTransaction(function (err) {
if (err) {
console.log(" --- error 1: " + JSON.stringify(err));
}

console.log(" --- A");

connection.query('update course_person set rescheduled_date = CURDATE() where idperson = ? and rescheduled_date is null', [idperson], function (err, rows, fields) {

if (err) {
connection.rollback(function () {
console.log(" --- error 2: " + JSON.stringify(err));
});

console.log(" --- B");

}

console.log(" --- C");

});

connection.query('insert into course_person (idcourse, idperson) VALUES (?, ?)', [newidcourse, idperson], function (err, rows, fields) {

if (err) {
connection.rollback(function () {
console.log(" --- error 3: " + JSON.stringify(err));
});

console.log(" --- D");

}

console.log(" --- E");

});

connection.commit(function (err) {
if (err) {
connection.rollback(function () {
console.log(" --- error 4: " + JSON.stringify(err));
});

console.log(" --- F");

}

console.log(" --- G");

req.flash('success', 'Person was updated successfully.');
res.redirect('/person/' + idperson);

connection.release();
});

});

});

我得到以下输出序列:

 --- A
--- C
--- D
--- E
--- G
--- error 3: {"code":"ER_DUP_ENTRY","errno":1062,"sqlState":"23000","index":0}

这是我的证明:)

enter image description here

最佳答案

如果您希望异步函数按顺序运行,则必须嵌套它们,或者将它们作为 Promise 数组的一部分调用,或者使用 async/await 样式代码...之类的东西。你在这里所做的就是调用

  1. pool.getConnection
  2. connection.beginTransaction
  3. 同时进行connection.query、connection.query和connection.commit

我突然想到,我会尝试这样的事情:

router.get('/myfunc', async (req, res) => {

try {

const connection = await pool.getConnection();

try {

await connection.beginTransaction();

// update statement
const sql_update = `update course_person
set rescheduled_date = CURDATE()
where idperson = ?
and rescheduled_date is null`;
await connection.query(sql_update, [idperson]);

// insert statement
const sql_insert = `insert into course_person (idcourse, idperson) VALUES (?, ?)`;
await connection.query(sql_insert, [newidcourse, idperson]);

// commit
await connection.commit();

req.flash('success', 'Person was updated successfully.');
return res.redirect('/person/' + idperson);

} finally {
pool.releaseConnection(connection);
}

} catch (err) {
await connection.rollback();
console.log(err);
}

});

注意:我还没有测试过这段代码。但这是我使用的模式。

这将要求您使用 Promise-mysql 而不是 Node-mysql,因为 async/await 语法需要使用 Promise。您还可以使用 Bluebird 来 promisify node-mysql。另外,如果你的 Node 版本还不支持 async/await,你需要使用 babel 之类的东西来将其转译下来。 (我在工作流程中使用 babel。)

如果您想简单地嵌套异步调用,对于更传统的编码风格,您可以执行以下操作:

pool.getConnection(function (err, connection) {

connection.beginTransaction(function (err) {
if (err) {
console.log(" --- error 1: " + JSON.stringify(err));
throw err;
}

connection.query('update course_person set rescheduled_date = CURDATE() where idperson = ? and rescheduled_date is null', [idperson], function (err, rows, fields) {
if (err) {
connection.rollback(function () {
console.log(" --- error 2: " + JSON.stringify(err));
throw err;
});
}

connection.query('insert into course_person (idcourse, idperson) VALUES (?, ?)', [newidcourse, idperson], function (err, rows, fields) {
if (err) {
connection.rollback(function () {
console.log(" --- error 3: " + JSON.stringify(err));
throw err;
});
}

connection.commit(function (err) {
if (err) {
connection.rollback(function () {
console.log(" --- error 4: " + JSON.stringify(err));
throw err;
});
}

req.flash('success', 'Person was updated successfully.');
res.redirect('/person/' + idperson);

connection.release();
});
});
});
});
});

请注意每个调用如何嵌套在前一个调用的回调函数中。所有的缩进都开始变得困惑(即“回调 hell ”)。从长远来看,使用 Promise 或 async/await 的代码更具可读性并且更易于维护。

关于node.js - Node -mysql事务在唯一键违规后不会回滚,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42679566/

29 4 0