9

複数のクエリとコミットメントに pqxx::work を使用したいのですが、コミット機能により、再度使用することはできません。簡単な例を次に示します。

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=pqxx::work(G_connexion) などの後続の等価物で G_work をリセットできますか? また、1 つの不正な要求によってプロセス全体がクラッシュすることはなく、処理中の 1 つだけがクラッシュするはずです (G_work は失敗後も使用可能です)。

プログラム内の多くの場所から呼び出されるグローバル変数になるため、同じ変数 G_Work を保持する必要があります。

4

1 に答える 1

16

pqxx::workpqxx::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 は接続オブジェクトのクラスではなく、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ありません。これは、セーブポイントが必要な場合に特に当てはまります。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;");
}
于 2014-11-19T14:26:05.650 に答える