【问题标题】:Sequelize: findOne auto commits during transaction (using clsHooked)Sequelize:findOne 在事务期间自动提交(使用 clsHooked)
【发布时间】:2019-06-29 08:38:54
【问题描述】:

我有类似下面的代码:

const _addEvents = async(eventList, day, transaction) => {
  await eventList.forEach(event => {
    return model.events.findOne({where:event, transaction: transaction}).then(event => {
        if(!event) {
          transaction.rollback();
          throw new Error("event not found");
        }

        return event;
      })
      .then(event => {
        day.addEvents(event, {through: {status: 'ENABLED'}});
        day.save();
      })
    })
  }
}

export const create = async(attributes) => {
        return await sequelize.transaction(async(t) => {
            return model.days.create(attributes, {transaction: t})).then(async(day) => {
                await _addEvents(attributes.eventList, day, t);
                return day;
            })
        })
}

我看到的是交易开始,并且在交易中的天数中添加了一行。在第一次迭代中,当在方法 _addEvents 中调用 findOne 时,事务被提交。

我使用了Sequelize.useCLS("foo");,所以我希望所有事务都在同一个命名空间中但是我传递事务只是为了确定。

谁能告诉我为什么事务在findOne 执行后提交,并告诉我如何避免这种情况发生。

我正在使用 (babel-core 6.26.3) 和 node.js v9.2.0 和 postgres 10.5

【问题讨论】:

    标签: node.js transactions sequelize.js


    【解决方案1】:

    感谢@Jan Aagaard Meier & Co 揭露问题。

    我的问题是await eventList.forEach 没有做到我希望它会做的事情。

    Array.prototype.forEach 将返回 undefined。它将返回与循环内的 Promise 状态无关。

    因此发生 COMMIT 是因为事务功能在丢失的 Promise(循环内)完成之前完成。

    一种解决方案是使用bluebird's Promise.map 将这条线变成

    await Promise.map(eventList, async(event) => {
        await model.events.findOne({where:event, transaction: transaction}).then(event => {
        ....
        }
    });
    

    在这里,map 将等待所有子 Promise 完成,并且当我们返回 Promise(并在其上等待)时,我们确保在 map 完成之前不会完成事务。

    【讨论】:

      【解决方案2】:

      _addEvents 正在做异步工作,但sequelize.transaction 不知道它需要等待它完成。 CLS 负责将事务传递到嵌套上下文中,但您仍需要确保您正在等待所有查询完成。

      await _addEvents(attributes.eventList, day, t);

      model.days.create 中,您需要将事务作为第二个参数传递,参见http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-create

      一般来说,我会推荐使用或者 CLS,或者在任何你使用它的地方传递事务。

      【讨论】:

      • 谢谢。我只是为了清楚起见而通过交易,但如果我不这样做,我知道 CLS 会处理它。我已经更新了示例,因为您的 cmets 语法是正确的,并且我按照建议添加了 async / await。问题仍然存在。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-25
      相关资源
      最近更新 更多