如何在JavaScript中使用具有异步函数的数据库事务?
考虑下面的代码,它从外部服务获取一些数据并将其插入数据库中的某个表中。它启动事务并在插入所有数据时提交,或者在发生错误时回滚事务:如何在JavaScript中使用具有异步函数的数据库事务?,javascript,node.js,Javascript,Node.js,考虑下面的代码,它从外部服务获取一些数据并将其插入数据库中的某个表中。它启动事务并在插入所有数据时提交,或者在发生错误时回滚事务: const mysql = require('mysql2/promise'); class SomeClass { async connect(params) { this.db = await mysql.createConnection(params); } async insertSomeRowsIntoS
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;');
}
}
}
constmysql=require('mysql2/promise');
上课
{
异步连接(参数)
{
this.db=wait mysql.createConnection(params);
}
异步insertSomeRowsIntoSomeTable()
{
等待这个.db.execute('START TRANSACTION;');
试一试{
for(设i=0;i<100;i++){
//例如,从外部服务获取要插入的值。
wait const values=service.getValues();
等待这个.db.execute('insertsometable……');
}
等待这个.db.execute('COMMIT;');
}
捕获(e){
等待这个.db.execute('ROLLBACK;');
}
}
}
但是,如果有另一个异步方法updatemething
使用单个更新查询更新某个表中的行,并且客户机在insertsomerowsintosotebase
方法仍在运行时调用该方法,该怎么办?显然,如果在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();
}
}
}
constmysql=require('mysql2/promise');
上课
{
异步连接(参数)
{
this.db=mysql.createPool(params);
}
异步insertSomeRowsIntoSomeTable()
{
const connection=wait this.db.getConnection();
等待连接。执行('START TRANSACTION;');
试一试{
for(设i=0;i<100;i++){
//例如,从外部服务获取要插入的值。
const values=await service.getValues();
等待conn.execute('INSERT SomeTable……');
}
等待连接。执行('COMMIT');
等待连接。释放();
}
捕获(e){
等待连接。执行('ROLLBACK');
等待连接。释放();
}
}
}
在这里,您从
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();
}
}
}
constmysql=require('mysql2/promise');
上课
{
异步连接(参数)
{
this.db=mysql.createPool(params);
}
异步insertSomeRowsIntoSomeTable()
{
const connection=wait this.db.getConnection();
等待连接。执行('START TRANSACTION;');
试一试{
for(设i=0;i<100;i++){
//例如,从外部服务获取要插入的值。
const values=await service.getValues();
等待conn.execute('INSERT SomeTable……');
}
等待连接。执行('COMMIT');
等待连接。释放();
}
捕获(e){
等待连接。执行('ROLLBACK');
等待连接。释放();
}
}
}
在这里,您可以从insertSomeRowsIntoSomeTable()中的池借用连接,如果其他异步函数遵循相同的模式,则此连接将仅由一个事务代码路径独占使用,直到释放为止请查看不要使用单个共享连接(您称之为db
)对于实例的所有方法。在每个事务/方法的连接上使用,并将它们池化。看一看不要对实例的所有方法使用单个共享连接(您称之为db
)。在每个事务/方法的连接上使用,并将其池化。