2014-10-20 7 views
6

Ich möchte ein pqxx :: arbeiten für mehrere Abfragen und Verpflichtungen, während die commit Funktion verhindern, dass ich es wieder verwenden. Hier ist ein einfaches Beispiel:pqxx wiederverwenden/reaktivieren eine Arbeit Transaktion

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

Wenn ich versuche, den ‚Bar‘ Wert einfügen, nach dem Commit, erhalte ich ein pqxx :: usage_error: Error executing query . Attempt to activate transaction<READ COMMITTED> which is already closed

Wie kann ich vermeiden, dass die Verbindung schließen nachdem ich die Änderungen vorgenommen habe? Kann ich G_work mit einem folgenden Äquivalent von G_work = pqxx :: work (G_connexion) zurücksetzen? Außerdem sollte eine ungültige Anforderung nicht den gesamten Prozess abstürzen lassen, sondern nur den in Bearbeitung befindlichen (G_work kann nach einem Fehler weiterhin verwendet werden).

Ich muss die gleiche Variable G_Work behalten, weil es eine globale Variable sein wird, die von vielen Stellen im Programm aufgerufen wird.

+0

Haben Sie gefunden, eine Antwort? – Michael

+0

Nein. Da niemand eine Antwort zu haben scheint, füge ich jeder Klasse in meiner Software eine Datenbankklasse hinzu und gebe sie bei Bedarf durch Methoden weiter. Eine eindeutige globale Transaktion war zu gefährlich, da ich sie nicht erneut aktivieren konnte, wenn sie fehlschlug. – alexis

Antwort

7

pqxx::work ist nur eine pqxx::transaction<>, die schließlich die meisten ihrer Logik von pqxx::transaction_base bekommt.

Diese Klasse ist nicht für mehrere Transaktionen vorgesehen. Stattdessen ist es für eine einzelne Transaktion innerhalb eines try/catch-Blocks vorgesehen. Es hat eine Statuselementvariable (m_Status), die selbst nach einem Commit nie neu initialisiert wird.

Das normale Muster:

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

Argumentieren, libpqxx die Transaktion beim Löschen Rollback könnte (die versuchen zu vermeiden/fangen ganz), aber es funktioniert nicht.

Es scheint, dass dies nicht Ihrem Verwendungsmuster entspricht, da Sie G_work eine globale Variable sein möchten, die von mehreren Stellen in Ihrem Programm zugänglich ist. Bitte beachten Sie, dass pqxx :: work nicht die Klasse für Verbindungsobjekte ist, sondern nur eine Möglichkeit, um begin/commit/rollback mit C++ - Ausnahmen zu kapseln.

Dennoch ermöglicht es libpqxx auch, Anweisungen außerhalb von Transaktionen auszuführen (oder zumindest außerhalb von von libpqxx verwalteten Transaktionen). Sie sollten Instanzen der Klasse pqxx::nontransaction verwenden.

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

Bitte beachten Sie, dass dies entspricht:

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

Schließlich nichts hindert Sie Transaktionen mit pqxx::nontransaction zu verwalten. Dies gilt insbesondere, wenn Sie savepoints möchten. Ich würde auch empfehlen, pqxx::nontransaction zu verwenden, wenn Ihre Transaktion über einen Funktionsumfang hinaus dauern soll (z. B. im globalen Gültigkeitsbereich).

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

Ok aber mit pqxx :: nontransaction class verliere den transaktionalen Teil, den ich behalten möchte. Tatsächlich möchte ich so etwas wie Checkpoints: Wenn die sohftware als einige wichtige Punkte erreicht, kann sie einreichen/Rollback, und dann halten Sie sich mit dem gleichen globalen Verbindung gehen. – alexis

+0

Sie können Transaktionen mit pqxx :: nontransaction selbst verwalten. Ich habe die Antwort entsprechend bearbeitet. –

+0

Ok ich dachte schon, sogar mit pqxx :: transaction konnte ich _exec ("commit"); exec ("begin") _ anstelle von G_work.begin(), was löst das Problem. Trotzdem muss ich die Verbindung im Falle einer fehlgeschlagenen Anfrage zurücksetzen können, ohne die Software zurückzusetzen. Zum Beispiel, wenn ich aufgrund einer Einschränkung keine Zeile einfügen kann, muss ich in der Lage sein, die anderen Aktionen fortzusetzen. – alexis