pqxx повторное использование / повторная активация рабочей транзакции

Я хочу использовать pqxx::работа для кратных запросов и обязательств, в то время как commit функция предотвращает меня от использования его снова. Вот простой пример :

pqxx::connection G_connexion("dbname=basetest user=usertest password=1234");
pqxx::work G_work(G_connexion);

int main(int argc, char* argv[]) {
    G_work.exec("insert into test.table1(nom) VALUES('foo');");
    G_work.commit();//until here, no problem
    G_work.exec("insert into test.table1(nom) VALUES('bar');"); //error, transaction already closed
    G_work.commit();
}

когда я пытаюсь вставить значение " bar " после фиксации, я получаю pqxx:: usage_error:Error executing query . Attempt to activate transaction<READ COMMITTED> which is already closed

Как я могу избежать закрытия соединения после фиксации изменений ? я могу сбросить G_work с successing эквивалент G_work=pqxx::работа(G_connexion), или другие ? Кроме того, один плохой запрос не должен завершать весь процесс, только тот, который находится в процессе (G_work все еще можно использовать после сбоя).

Я должен сохранить ту же переменную G_Work, потому что это будет глобальная переменная, вызываемая из множества мест в программе.

1 ответов


pqxx::work это просто pqxx::transaction<> который в конечном итоге получает большую часть своей логики от pqxx::transaction_base.

этот класс не предназначен для обслуживания нескольких транзакций. Вместо этого он предназначен для одной транзакции в блоке try/catch. Он имеет переменную-член состояния (m_Status), который никогда не обновляется, даже после фиксации.

нормальный шаблон:

{
    pqxx::work l_work(G_connexion);
    try {
        l_work.exec("insert into test.table1(nom) VALUES('foo');");
        l_work.commit();
    } catch (const exception& e) {
        l_work.abort();
        throw;
    }
}

возможно, libpqxx может откатить транзакцию при удалении (до избегайте try / catch полностью), но это не так.

кажется, что это не соответствует вашему шаблону использования, как вы хотите G_work быть глобальной переменной, доступной из нескольких мест в вашей программе. Обратите внимание, что pqxx::work-это не класс для объектов подключения, а просто способ инкапсуляции begin/commit/rollback с обработкой исключений C++.

тем не менее, libpqxx также позволяет выполнять инструкции вне транзакций (или, по крайней мере, вне libpqxx-управляемых сделки.) Вы должны использовать экземпляры pqxx::nontransaction класса.

#include "pqxx/nontransaction"

pqxx::connection G_connexion("dbname=basetest user=usertest password=1234");
pqxx::nontransaction G_work(G_connexion);

int f() {
    G_work.exec("insert into test.table1(nom) VALUES('foo');");
    G_work.exec("insert into test.table1(nom) VALUES('bar');");
}

обратите внимание, что это эквивалентно:

#include "pqxx/nontransaction"

pqxx::connection G_connexion("dbname=basetest user=usertest password=1234");

int f() {
    pqxx::nontransaction l_work(G_connexion);
    l_work.exec("insert into test.table1(nom) VALUES('foo');");
    l_work.exec("insert into test.table1(nom) VALUES('bar');");
}

в итоге ничто не мешает вам управлять сделками С pqxx::nontransaction. Это особенно верно, если вы хотите savepoints. Я бы также посоветовал использовать pqxx::nontransaction если ваша транзакция должна длиться за пределами области функций (например, в глобальной области).

#include "pqxx/nontransaction"

pqxx::connection G_connexion("dbname=basetest user=usertest password=1234");
pqxx::nontransaction G_work(G_connexion);

int f() {
    G_work.exec("begin;");
    G_work.exec("insert into test.table1(nom) VALUES('foo');");
    G_work.exec("savepoint f_savepoint;");
    // If the statement fails, rollback to checkpoint.
    try {
        G_work.exec("insert into test.table1(nom) VALUES('bar');");
    } catch (const pqxx::sql_error& e) {
        G_work.exec("rollback to savepoint f_savepoint;");
    }
    G_work.exec("commit;");
}