pqxx reuse / reactivate a work transaction

匿名 (未验证) 提交于 2019-12-03 01:17:01

问题:

I want to use a pqxx::work for multiples queries AND commitments, while the commit function prevent me from using it again. Here is a simple example :

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

When I try to insert the 'bar' value, after the commit, I get a pqxx::usage_error : Error executing query . Attempt to activate transaction<READ COMMITTED> which is already closed

How can I avoid to close the connection after I commit the changes ? can i reset G_work with a successing equivalent of G_work=pqxx::work(G_connexion), or other ? Also, one bad request should not crash the entire process, just the one in process (G_work still usable after a failure).

I have to keep the same variable G_Work because it will be a global variable called from lots of places in the program.

回答1:

pqxx::work is just a pqxx::transaction<> which eventually gets most of its logic from pqxx::transaction_base.

This class is not intended to serve for several transactions. Instead, it is intended for a single transaction within a try/catch block. It has a state member variable (m_Status) which is never reinitialized, even after a commit.

The normal pattern is:

{     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;     } } 

Arguably, libpqxx could rollback the transaction on deletion (to avoid the try/catch entirely) but it doesn't.

It seems that this doesn't fit your usage pattern as you want G_work to be a global variable accessible from several places in your program. Please note that pqxx::work is not the class for connection objects, but just a way to encapsulate begin/commit/rollback with C++ exceptions handling.

Nevertheless, libpqxx also allows you to execute statement outside transactions (or at least outside libpqxx-managed transactions). You should use instances of pqxx::nontransaction class.

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

Please note that this is equivalent to:

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

Eventually, nothing prevents you to manage transactions with pqxx::nontransaction. This is especially true if you want savepoints. I would also advise using pqxx::nontransaction if your transaction is meant to last beyond a function scope (e.g. at global scope).

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!