【问题标题】:How to use database transactions in JavaScript with async functions?如何在 JavaScript 中通过异步函数使用数据库事务?
【发布时间】:2019-10-30 21:14:53
【问题描述】:

考虑下面的代码,它从外部服务获取一些数据并将其插入到数据库中的某个表中。它启动事务并在插入所有数据时提交它,如果发生错误则将其回滚:

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出现错误,更新后的数据将会丢失。

如果有其他方法发起自己的事务,例如我们意外得到嵌套事务。

我目前唯一的想法是通过将所有事务逻辑移动到存储过程来使数据库的所有操作成为原子操作,但它看起来像是一种解决方法,但不是解决方案。

出于显而易见的原因,不能在每个异步方法中使用单独的数据库连接。

有人有更好的主意吗?

【问题讨论】:

标签: javascript node.js


【解决方案1】:

可能最简单的解决方案是使用池:

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() 中的池中借用连接,如果其他异步函数遵循相同的模式,则此连接将仅由一个事务代码路径独占使用,直到释放

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    相关资源
    最近更新 更多