2017-11-17 10 views
1

MS SQL Server 2008. Qt + ODBC。transaction()は@@ TRANCOUNTをインクリメントしません。

私は、最高レベルのトランザクションをロールバックすることでデータベース内のいくつかの変更(内部で行われた)をロールバックしようとしています。しかし、私の2番目のdb.transaction()呼び出しが@@ TRANCOUNTをインクリメントせず、最初のコミット(内部)クローズトランザクションが完全に完了していないようです。このため、外部トランザクション・レベルの次のロールバック・コマンドは無視されます。

いくつかの例です。

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 

テストコード:

... 
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 

デバッグ出力:

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()関数:

static int Num = 0; 
query->exec("SELECT @@TRANCOUNT");query->first(); 
qDebug() << "Transaction Count "<< Num << ": " <<query->value(0).toInt(); 
Num++; 
TRANCOUNTがeachoperation後DBから受信@@コメント文字列が表示され

番目トランザクションカウンタ(@@ TRANCOUNT)が2回目のトランザクション後に2に増加しない何らかの理由がありますか?私は取引カウンターの考え方を正しく理解していませんでしたか?または、データベース/ドライバの設定に問題がありますか?たぶん、私が逃した私の例のコードにいくつかのエラーがありますか?

私はどんなヒントでも感謝しています。 Googleのため申し訳ありませんが翻訳し:)

+0

任意の「内側」トランザクションのコミットの意味でのSQL Serverには、ネストされたトランザクションが何もコミットしていない(唯一増加@@ TRANCOUNTを)し、任意の「内側」のロールバックロールは、すべてのバックアップがあります。 – sepupic

+0

ここをクリックしてください:https://www.sqlskills.com/blogs/paul/a-sql-server-dba-myth-a-day-2630-nested-transactions-are-real/ – sepupic

+0

申し訳ありませんが、私はしていません問題を適切に記述する私の場合(上記の '1' '2' '3'インサートの場合)、まったくロールバックされた操作はありません。あなたのコメントの記事によると、外部ロールバックは内部トランザクションでコミットされた操作を取り消すべきです。しかし、これは起こりません。私はTestOnlyテーブルに3つの行を持っています。私は、データベースが内部取引をまったく開始しないように見えるので、すぐに取引カウンタについて質問することにしました。 – Eventus

答えて

0

すべては、ソースコード表示することによって解決されました:

db.transactionを()データベース(少なくともODBCドライバを使用)に任意の「始めるTRAN」コマンドを送信しません。この関数はコミットモードを "manual commit mode"に変更するだけです。その後、最初のdb.commit()は( "SQLEndTran"コマンドを送信して)すべての変更を確認し、モードを再び "自動コミットモード"に戻します。

"入れ子"(実際に入れ子になっていない)トランザクションを@@ TRANCOUNTで使用するには、データベースに "tran begin"/"commit"/"rollback"コマンドを手動で送信すれば十分です。私の例では:

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 
関連する問題