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