Intereting Posts

pqxx повторно использовать / активировать рабочую транзакцию

Я хочу использовать pqxx :: work для кратких запросов и обязательств, в то время как функция 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 :: use_error: Error executing query . Attempt to activate transaction which is already closed Error executing query . Attempt to activate transaction which is already closed

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

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

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

Этот class не предназначен для нескольких транзакций. Вместо этого он предназначен для одной транзакции в блоке try / catch. Он имеет переменную члена состояния ( m_Status ), которая никогда не 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 может отменить транзакцию при удалении (чтобы избежать попытки / catch целиком), но это не так.

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

Тем не менее libpqxx также позволяет выполнять оператор внешних транзакций (или, по крайней мере, за пределами транзакций, управляемых libpqxx). Вы должны использовать экземпляры classа 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 . Это особенно верно, если вы хотите сохранять точки . Я бы также посоветовал использовать 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;"); }