Sequelize: findOne автоматически фиксирует транзакцию (используя clsHooked) - PullRequest
0 голосов
/ 05 февраля 2019

У меня есть код, подобный приведенному ниже:

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;
            })
        })
}

Я вижу, что транзакция начинается, и в дни транзакции добавляется строка.На первой итерации, когда findOne вызывается в методе _addEvents, транзакция фиксируется.

Я использовал Sequelize.useCLS("foo");, поэтому я ожидаю, что все транзакции будут в одном и том же пространстве имен однако Я передаю транзакцию, просто чтобы быть уверенным.

Может кто-нибудь сказать мне, почему транзакция совершается после выполнения findOne, и при этом сказать мне, как избежать этого.

Я использую (babel-core 6.26.3) и node.js v9.2.0 & postgres 10.5

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Спасибо @ Jan Aagaard Meier & Co за выявление проблемы.

Моя проблема заключалась в том, что await eventList.forEach не делал то, что я надеялся , что он будет делать.

Array.prototype.forEach вернет undefined.Он будет возвращать значение, не зависящее от состояния обещаний в цикле.

Следовательно, COMMIT происходит потому, что функция транзакции завершается до того, как потерянные обещания (в цикле) могут завершиться.

Решениедолжен использовать Promise.map * bluebird , который превращает эту строку в

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

Здесь карта будет ждать, пока все подчиненные Обещания завершатся, и когда мы вернем Обещание (и ожидаем его)мы гарантируем, что не завершим транзакцию до завершения карты.

0 голосов
/ 05 февраля 2019

_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, либо передавать транзакцию везде, где вы ее используете.

...