[英]How to use database transactions in JavaScript with async functions?
考虑下面的代码,它从外部服务获取一些数据并将其插入到数据库中的某个表中。 它启动事务并在插入所有数据时提交它,如果发生错误则将其回滚:
const mysql = require('mysql2/promise');
class SomeClass
{
async connect(params)
{
this.db = await mysql.createConnection(params);
}
async insertSomeRowsIntoSomeTable()
{
await this.db.execute('START TRANSACTION;');
try {
for (let i = 0; i < 100; i++) {
//get the values to insert from an external service, for example.
await const values = service.getValues();
await this.db.execute('INSERT SomeTable .... <the values>...');
}
await this.db.execute('COMMIT;');
}
catch (e) {
await this.db.execute('ROLLBACK;');
}
}
}
但是,如果有另一个异步方法updateSomething
使用单个更新查询更新某个表中的一行,并且客户端在insertSomeRowsIntoSomeTable
方法仍在运行时调用它,该怎么办? 显然,如果insertSomeRowsIntoSomeTable
发生错误,更新的数据将会丢失。
如果有另一种方法发起自己的事务,例如,我们意外地得到了嵌套事务。
例如,我目前唯一的想法是通过将所有事务逻辑移动到存储过程来使数据库的所有操作成为原子操作,但这看起来像是一种解决方法,但不是解决方案。
出于显而易见的原因,在每个异步方法中都有一个单独的数据库连接不是一种选择。
有没有人有更好的主意?
可能最简单的解决方案是使用池:
const mysql = require('mysql2/promise');
class SomeClass
{
async connect(params)
{
this.db = mysql.createPool(params);
}
async insertSomeRowsIntoSomeTable()
{
const connection = await this.db.getConnection();
await connection.execute('START TRANSACTION;');
try {
for (let i = 0; i < 100; i++) {
//get the values to insert from an external service, for example.
const values = await service.getValues();
await conn.execute('INSERT SomeTable .... <the values>...');
}
await connection.execute('COMMIT');
await connection.release();
}
catch (e) {
await connection.execute('ROLLBACK');
await connection.release();
}
}
}
在这里,您从insertSomeRowsIntoSomeTable()
中的池中借用连接,如果其他异步函数遵循相同的模式,则此连接将仅由一个事务代码路径独占使用,直到释放
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.