Должна ли каждая команда Knex в транзакции быть отправлена ​​только после выполнения обещания предыдущей команды, если их порядок важен? - PullRequest
0 голосов
/ 12 февраля 2020

Я использую вторую форму транзакций knex (например, с «транзакцией»). Тем не менее, этот вопрос, вероятно, действителен и для первой формы.

Пример документации показывает это:

// Using trx as a transaction object:
knex.transaction(function(trx) {

  const books = [
    {title: 'Canterbury Tales'},
    {title: 'Moby Dick'},
    {title: 'Hamlet'}
  ];

  knex.insert({name: 'Old Books'}, 'id')
    .into('catalogues')
    .transacting(trx)
    .then(function(ids) {
      books.forEach((book) => book.catalogue_id = ids[0]);
      return knex('books').insert(books).transacting(trx);
    })
    .then(trx.commit)
    .catch(trx.rollback);
})

В транзакции выполняются две команды "вставки". Второй отправляется только после того, как обещание первого выполнено (т. Е. В обратном вызове обещания then).

В приведенном выше примере это необходимо, поскольку вторую команду можно сформулировать только после результат первой команды вернулся.

Однако бывают случаи, когда несколько команд могут быть сформулированы заранее. Таким образом, можно выполнить код, подобный следующему:

promise1 = knex('table1').insert(...).transacting(trx).then(...)
promise2 = knex('table2').insert(...).transacting(trx).then(...)

Use Promise.all to wait for completion and eventually commit or rollback.

Фактически этот код будет выполняться. Knex будет ставить команды в очередь и отправлять их по соединению, назначенному для транзакции, по одной за раз.

Однако , и это суть моего вопроса , эмпирическое доказательство при использовании knex с PostgreSQL, кажется, показывает, что порядок, в котором команды отправляются в базу данных, не поддерживается. Другими словами, порядок, в котором команды были отправлены в knex, не обязательно является порядком, в котором они отправляются в базу данных. Похоже, что единственный способ гарантировать, что команды отправляются в определенном порядке c, - создать цепочку обещаний, в которой каждая команда представляется только после выполнения предыдущей команды.

Может кто-нибудь прокомментировать это ? Это по замыслу? Может ли это быть ошибкой?

1 Ответ

0 голосов
/ 14 февраля 2020

Однако, и это суть моего вопроса, эмпирические данные при использовании knex с PostgreSQL, похоже, показывают, что порядок, в котором команды отправляются в базу данных, не поддерживается. Другими словами, порядок, в котором команды были отправлены в knex, не обязательно является порядком, в котором они отправляются в базу данных. Похоже, что единственный способ гарантировать, что команды отправляются в определенном порядке c, - создать цепочку обещаний, в которой каждая команда отправляется только после выполнения предыдущей команды.

Похоже ваш код не делает то, что вы думаете.

Knex отправляет запросы драйверу базы данных в том порядке, как вы говорите ему выполнять их (await с помощью построителя запросов или путем выполнения .then() method).

Если вы выполнили более 1 запроса к одной и той же транзакции, прежде чем завершится предыдущий, node-pg драйвер буферизует второй запрос и отправляет его только после того, как первый запрос впервые вернул свой ответ.

Используйте Promise.all, чтобы дождаться завершения и, в конечном итоге, зафиксировать или откатить.

Если не выдано никакой ошибки, это должно сработать.

Promise.all([p1,p2fails,p3,p4,p5])

Однако, если возникает исключение, например, из обещания p2fails, Promise.all будет немедленно отклонено и rollback будет выполнено. После этого p3, p4 и p5 все еще пытаются выполнить, так как они уже были помещены в буфер в node-pg для отправки.

Будет безопаснее, эффективнее память (запрос сохраняется дважды, один раз в конструкторе knex и один раз как буферизованный необработанный запрос в драйвере pg с большими вставками, это может быть важно), и проще просто подождать возврата каждого запроса перед отправкой следующего. Использование Promise.all здесь даже не дает никаких дополнительных преимуществ параллелизма, поскольку запросы по-прежнему выполняются последовательно через одно и то же соединение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...