2017-11-17 1 views
1

MS SQL Server 2008. Qt + ODBC.transaction() erhöht nicht @@ TRANCOUNT?

Ich versuche Rollback einige Änderungen (die in inneren gemacht wurden) in der Datenbank durch Rollback-Transaktion der höchsten Ebene. Aber es sieht so aus, als würde mein zweiter db.transaction() - Aufruf die Transaktion "@@ TRANCOUNT" und die erste (innere) "commit" - Transaktion vollständig inkrementieren. Aus diesem Grund wird der nächste Rollback-Befehl auf der Ebene der äußeren Transaktion ignoriert.

Ein Beispiel. Kommentierten strings anzuzeigen @@ TRANCOUNT von DB nach eachoperation erhalten:

db.transaction();          //@@TRANCOUNT = 0 
query->exec("INSERT INTO TestOnly (Value) VALUES('1')");//@@TRANCOUNT = 1 
db.transaction();          //@@TRANCOUNT = 1 
query->exec("INSERT INTO TestOnly (Value) VALUES('2')");//@@TRANCOUNT = 1 
db.commit();           //@@TRANCOUNT = 0 
query->exec("INSERT INTO TestOnly (Value) VALUES('3')");//@@TRANCOUNT = 0 
db.rollback();           //@@TRANCOUNT = 0 

Testcode:

... 
db = QSqlDatabase::addDatabase("QODBC3"); 
... 
query = new QSqlQuery(db); 
... 

bool ok; 
ok = db.transaction(); qDebug() << "Start transaction" << " result = " << ok << "; errorText: " << db.lastError().text(); 
PrintTranCount(); //0 

query->exec("INSERT INTO TestOnly (Value) VALUES('1')"); 
PrintTranCount(); //1 

ok = db.transaction(); qDebug() << "Start transaction" << " result = " << ok << "; errorText: " << db.lastError().text(); 
PrintTranCount(); //2 

query->exec("INSERT INTO TestOnly (Value) VALUES('2')"); 
PrintTranCount(); //3 

ok = db.commit(); qDebug() << "Commit transaction" << " result = " << ok << "; errorText: " << db.lastError().text(); 
PrintTranCount(); //4 

query->exec("INSERT INTO TestOnly (Value) VALUES('3')"); 
PrintTranCount(); //5 

ok = db.rollback(); qDebug() << "Rollback transaction" << " result = " << ok << "; errorText: " << db.lastError().text(); 
PrintTranCount(); //6 

Debug output:

Start transaction result = true ; errorText: " " 
Transaction Count 0: 0 
Transaction Count 1: 1 
Start transaction result = true ; errorText: " " 
Transaction Count 2: 1 
Transaction Count 3: 1 
Commit transaction result = true ; errorText: " " 
Transaction Count 4: 0 
Transaction Count 5: 0 
Rollback transaction result = true ; errorText: " " 
Transaction Count 6: 0 

PrintTranCount() Funktion:

static int Num = 0; 
query->exec("SELECT @@TRANCOUNT");query->first(); 
qDebug() << "Transaction Count "<< Num << ": " <<query->value(0).toInt(); 
Num++; 

Ist th Gibt es einen Grund, warum der Transaktionszähler (@@ TRANCOUNT) nach der zweiten Transaktion nicht auf 2 erhöht wird? Ich habe die Idee des Transaktionszählers nicht richtig verstanden. Oder gibt es Probleme mit Datenbank/Treibereinstellungen? Vielleicht gibt es einige Fehler in meinem Beispielcode, den ich verpasst habe?

Ich werde für Hinweise dankbar sein. Sorry für Übersetzungs :)

+0

Es gibt keine verschachtelte Transaktion in SQL Server in Sinne, dass jede „inneren“ Transaktionscommit begeht nichts (nur erhöhen @@ trancount) und all „innere“ Rollback-Rolle sichert alle. – sepupic

+0

Bitte lesen Sie hier: https://www.sqlskills.com/blogs/paul/a-sql-server-dba-myth-a-day-2630-nested-transactions-are-real/ – sepupic

+0

Sorry, ich tat es nicht Problem richtig beschreiben. In meinem Fall (mit '1' '2' '3' Einsätzen, die oben beschrieben sind) gibt es keine Operation, die überhaupt zurückgerollt wurde. Laut einem Artikel aus Ihrem Kommentar sollte ein externer Rollback den in der internen Transaktion festgelegten Vorgang abbrechen. Aber das passiert nicht. Ich habe alle drei Reihen in TestOnly Tabelle. Ich entschied mich, sofort nach dem Transaktionszähler zu fragen, weil es so aussieht, als würde die Datenbank überhaupt keine interne Transaktion starten. – Eventus

Antwort

0

Alles durch Betrachten des Quellcodes aufgelöst wurde:

db.transaction() Bitte senden Sie keine „beginnen TRAN“ Befehl Datenbank (zumindest mit ODBC-Treiber). Diese Funktion ändert nur den Commit-Modus auf "manual commit mode". Danach bestätigt db.commit() zunächst alle Änderungen (indem der Befehl "SQLEndTran" gesendet wird) und wechselt wieder in den Modus "Auto Commit".

Um "verschachtelte" (nicht wirklich geschachtelte) Transaktionen mit @@ TRANCOUNT zu verwenden, reicht es aus, die Befehle "tran begin"/"commit"/"rollback" manuell an die Datenbank zu senden. In meinem Beispiel:

query->exec("begin tran");        //@@TRANCOUNT = 1 
query->exec("INSERT INTO TestOnly (Value) VALUES('1')");//@@TRANCOUNT = 1 
query->exec("begin tran");        //@@TRANCOUNT = 2 
query->exec("INSERT INTO TestOnly (Value) VALUES('2')");//@@TRANCOUNT = 2 
query->exec("commit");         //@@TRANCOUNT = 1 
query->exec("INSERT INTO TestOnly (Value) VALUES('3')");//@@TRANCOUNT = 1 
query->exec("rollback");        //@@TRANCOUNT = 0