【问题标题】:Use CLS with Sequelize Unmanaged transactions将 CLS 与 Sequelize 非托管事务一起使用
【发布时间】:2021-12-03 02:57:23
【问题描述】:

我正在为我的代码编写单元测试,并希望使用transactions 来防止测试之间出现任何杂散数据。

代码使用Sequelize ORM 进行与数据库的所有交互。由于更改实际代码不是一种选择,我将使用cls-hooked 来维护事务上下文,而不是将事务传递给所有查询。然而,有一个问题。在阅读官方文档并尝试进行操作时,上述方法似乎仅适用于托管事务。

到目前为止,测试代码看起来有点像:

test("Test decription", async () => {
    try {
        await sequelize.transaction(async (t) => {
            //Actual test code
        });
    } catch (error) {
        //Do nothing if query rolled back
    }
});

我打算实现的目标(原因很明显):

let t;

beforeEach(async () => {
    t = await sequelize.transaction();
});

test("Test decription", async () => {
    //Actual test code
});

afterEach(async () => {
    await t.rollback();
});

这可能吗?如果是,我们将不胜感激。

【问题讨论】:

  • 明显的原因 - 什么原因?第一个 sn-p 到底有什么问题?
  • @EstusFlask 对于​​每个测试,第一种方法需要启动一个事务并向测试本身添加一个 catch 块。第二种方法将导致更清晰的测试代码和更容易处理以及避免代码冗余。
  • 不久前看到一个类似的 CLS 问题,但找不到。我想解决方案就是这里讨论的,github.com/Jeff-Lewis/cls-hooked/issues/44

标签: mysql node.js jestjs sequelize.js cls-hooked


【解决方案1】:

我也遇到了同样的问题——经过多次谷歌搜索,我发现这个已关闭 issue 表明设计不支持非托管事务?

【讨论】:

    【解决方案2】:

    确实,当您使用非托管事务时,Sequelize 不会自动将事务传递给查询。但是您可以在 CLS 命名空间上手动设置事务属性,就像 Sequelize 在托管事务上所做的那样:

    https://github.com/sequelize/sequelize/blob/v6.9.0/lib/transaction.js#L135

    namespace.run(() => {
        namespace.set('transaction', transaction);
        /* run code that does DB operations */
    });
    

    这对于测试来说很棘手,因为 describe() 调用可以嵌套,并且每个调用都可以有自己的 beforeAll()/afterAll()beforeEach()/afterEach() 挂钩。要做到这一点,每个before 钩子都需要设置一个嵌套事务,并且相应的after 钩子应该回滚它。此外,测试用例本身需要在嵌套事务中运行,以免其 DB 操作泄漏到其他测试中。

    【讨论】:

      猜你喜欢
      • 2015-06-03
      • 2012-02-29
      • 2020-09-10
      • 2014-04-06
      • 2017-05-07
      • 2017-04-16
      • 2016-08-11
      • 2012-04-02
      • 2019-06-01
      相关资源
      最近更新 更多