简体   繁体   English

pqxx 重用/重新激活工作事务

[英]pqxx reuse / reactivate a work transaction

I want to use a pqxx::work for multiple queries AND commitments, while the commit function prevents me from using it again.我想将 pqxx::work 用于多个查询和承诺,而提交功能阻止我再次使用它。 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当我尝试插入 'bar' 值时,在提交后,我得到一个 pqxx::usage_error : Error executing query. Attempt to activate transaction<READ COMMITTED> which is already closed execution Error executing query. Attempt to activate transaction<READ COMMITTED> which is already closed 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 succeeding equivalent of G_work=pqxx::work(G_connexion), or other?我可以使用 G_work=pqxx::work(G_connexion) 或其他等价的后续等效项重置 G_work 吗? Also, one bad request should not crash the entire process, just the one in process (G_work still usable after a failure).此外,一个错误的请求不应该使整个进程崩溃,而只是进程中的一个(失败后 G_work 仍然可用)。

I have to keep the same variable G_Work because it will be a global variable called from lots of places in the program.我必须保留相同的变量 G_Work,因为它将是从程序中的很多地方调用的全局变量。

pqxx::work is just a pqxx::transaction<> which eventually gets most of its logic from pqxx::transaction_base . pqxx::work只是一个pqxx::transaction<> ,它最终从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.相反,它用于 try/catch 块中的单个事务。 It has a state member variable ( m_Status ) which is never reinitialized, even after a commit.它有一个状态成员变量 ( m_Status ),即使在提交之后也不会重新初始化。

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.可以说,libpqxx 可以在删除时回滚事务(以完全避免 try/catch),但事实并非如此。

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.这似乎不适合您的使用模式,因为您希望G_work成为可从程序中的多个位置访问的全局变量。 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.请注意 pqxx::work 不是连接对象的类,而只是一种用 C++ 异常处理封装开始/提交/回滚的方法。

Nevertheless, libpqxx also allows you to execute statement outside transactions (or at least outside libpqxx-managed transactions).尽管如此,libpqxx 还允许您在事务之外(或至少在 libpqxx 管理的事务之外)执行语句。 You should use instances of pqxx::nontransaction 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');");
}

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 .最终,没有什么可以阻止您使用pqxx::nontransaction管理事务 This is especially true if you want savepoints .如果您想要savepoints ,则尤其如此。 I would also advise using pqxx::nontransaction if your transaction is meant to last beyond a function scope (eg at global scope).如果您的事务打算持续超出函数范围(例如在全局范围内),我还建议使用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;");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM