Как подзапросы, содержащиеся в запросах, работают в pg-promise при использовании транзакций?

Я использую pg-promise для node.js и хотел убедиться, что правильно понимаю документацию о транзакциях.

Скажем, я выполнил следующую транзакцию:

db.tx(function(t) {
  t.any('SELECT * FROM users')
  .then(function(users) {
    var queries = [];
    for (var i =0; i < users.length; i++) {
      queries.push(t.any("INSERT INTO stocks_owned (ticker, shares, user_id) VALUES ('GOOG', 10, $1)", users[i].user_id));
    }
    return t.batch(queries);
  })
})

Какие запросы postgres это в конечном итоге будет выполнять?

Будет ли транзакция postgres:

BEGIN;
SELECT * FROM users;
SAVEPOINT my_savepoint;
INSERT INTO stocks_owned (ticker, shares, user_id) VALUES ('GOOG', 10, 1);
INSERT INTO stocks_owned (ticker, shares, user_id) VALUES ('GOOG', 10, 2);
...
INSERT INTO stocks_owned (ticker, shares, user_id) VALUES ('GOOG', 10, 999);
COMMIT;

Другими словами, включаются ли подзапросы, содержащиеся в других запросах, в один и тот же блок BEGIN/COMMIT?


person Charles Riley    schedule 07.08.2016    source источник


Ответы (1)


Какие запросы postgres это в конечном итоге будет выполнять?

Те, которые вы перечислили, за исключением того, что SAVEPOINT не будет, потому что вместо вложенных транзакций используются только точки сохранения.

включаются ли подзапросы, содержащиеся в других запросах, в один и тот же блок BEGIN/COMMIT?

Нет такой вещи, как подзапросы, с точки зрения драйвера, есть просто запросы, и все те, которые выполняются внутри транзакции, будут внутри блока BEGIN/COMMIT.


Чтобы увидеть, что именно выполняется pg-promise, вы должны использовать pg-monitor или как минимум - обработать запрос события:

var pgOptions = {
    query: function (e) {
        console.log(e.query); // log the query being executed
    }
};

var pgp = require('pg-promise')(pgOptions);

В вашем коде ошибка:

t.any('SELECT * FROM users')

что должно быть:

return t.any('SELECT * FROM users')

либо там нет логики транзакции, так как вы ничего не возвращаете из обратного вызова.

Самый короткий и эффективный способ сделать то, что вы там пытались:

db.tx(t => {
    return t.map('SELECT * FROM users', [], user => {
        return t.none("INSERT INTO stocks_owned(ticker, shares, user_id) VALUES('GOOG', 10, ${user_id})", user);
    }).then(t.batch);
})
    .then(data => {
        // success, data = [null, null, ...]
    })
    .catch(error => {
        // error
    });

ОБНОВЛЕНИЕ

Приведенный выше пример больше не является самым эффективным способом сделать это. Наиболее эффективным подходом будет выполнение одного выбора, а затем одной многострочной вставки. См. раздел Многострочные вставки.

person vitaly-t    schedule 07.08.2016
comment
Благодарю вас! Ваша упаковка великолепна, между прочим (без похабного каламбура). Ваше здоровье. - person Charles Riley; 08.08.2016
comment
Нет такой вещи, как подзапросы. Что ж, есть такая вещь, как подзапросы, но явно не на уровне node-pg. Подзапрос — это конструкция в SQL, в которой один запрос содержит другой, например. SELECT ... FROM ... WHERE x = (SELECT ...) или SELECT ... FROM (SELECT ..) - person Craig Ringer; 08.08.2016
comment
@CraigRinger Я исправил это, указав явно from the driver point of view, поскольку это то, что мы обсуждали, т. Е. Для драйвера это всегда просто запрос, независимо от его уровня. - person vitaly-t; 08.08.2016
comment
@CraigRinger добавил объяснение ошибки в вашем коде . - person vitaly-t; 10.08.2016