techbank.jp コミュニティ

     あれ?どうやるんだっけ?を解決する

坊やがゆくtech

トランザクションのネストと@@TRANCOUNTの関係、コミット/ロールバックについてまとめ

Microsoft TechNet「トランザクションのネスト」にて簡潔に説明されているので引用させていただきます。

@@TRANCOUNTのカウント(ざっくり)

  • BEGIN TRANSACTION ステートメントは @@TRANCOUNT を 1 ずつ増やします。
  • COMMIT TRANSACTION は @@TRANCOUNT を 1 ずつ減らします。
  • ROLLBACK TRANSACTION ステートメントは、ネストしたトランザクションがすべてロールバックされ、@@TRANCOUNT は 0 になります。
  • @@TRANCOUNT が 0 の場合は、トランザクションにいません。
http://technet.microsoft.com/ja-jp/library/aa213076(SQL.80).aspx

トランザクションの外側と内側の概念、超重要!

Microsoft SQL Server は、内部トランザクションのコミットを無視します。
トランザクションは、最も外側のトランザクションが終了したときの処理に基づいてコミットまたはロールバックされます。
外側のトランザクションがコミットされた場合、ネストした内部トランザクションもコミットされます。
外側のトランザクションがロールバックされた場合、内部トランザクションが個々にコミットされているかどうかに関係なく、内部トランザクションもすべてがロールバックされます。

http://technet.microsoft.com/ja-jp/library/aa213076(SQL.80).aspx

つまり一番外側のコミット/ロールバックに依存するということです。
※部分的にロールバックしたい場合はセーブポイントを使用します。

図説およびサンプルコード(英語)
http://www.vfpconversion.com/Article.aspx?quickid=0305111

内側のトランザクションのエラー処理などはクセがあるので上記のサンプルコードを参考にされると良いでしょう。
具体的には「内側のトランザクションではROLLBACKは発行せずにCOMMITで終了して戻り値で判断する。そしてROLLBACKは外側のトランザクションで行う。」です。

-- Normal exit
IF @@TRANCOUNT > 0
 COMMIT
RETURN(0)

-- Error Exit
ErrExit:
IF @@TRANCOUNT > 1
 COMMIT
ELSE
 IF @@TRANCOUNT = 1
  ROLLBACK
RETURN(-1)

参考:
SQL Server 2000でのコネクション/トランザクション問題
http://d.hatena.ne.jp/PoohKid/20060608/p2

コメント

 

けろ-みお 発言:

ネストされた内部トランザクションは無視されるわけですね。

たとえば、外側に大きなトランザクションがあり、内側には1件ずつループしながら、1件ずつコミットしているトランザクションがいたとします。この場合、内側で1件コミットしているトランザクションは、実はコミットされてなくて、外側のトランザクションによってコミットされるということですよね?

もし、内側のトランザクションで1件ずつコミットするようなループ処理を実現させたい場合は、セーブポイントを使いなさいってことになると思いますが、このセーブポイントの概念をT-SQLではなく、C#やVB.NETで実装したいという場合、どうなりますかね?

試して頂けると有難いです。

12月 9, 2009 10:40 午後
 

PoohKid 発言:

外側にトランザクションがある以上は基本的に外側の制御の影響を受けるということだと思います。

自宅のマシンがEeePCで開発環境が無いので実際に試すのは難しいのですが、C#やVB.NETで実装するのであればコネクションを別にすることで実現できると思います。

TransactionScopeだと分散トランザクションになってしまうのでコスト高になってしまいますが。

12月 10, 2009 2:22 午前

コメントを残す

(必須)  
(オプション)
(必須)  
techbank.jp