.netでのトランザクション


144

C#.Net 2.0でトランザクションを実行するためのベストプラクティスは何ですか。使用する必要があるクラスは何ですか?気を付けなければならない落とし穴などは何ですか。データをDBに挿入するときにトランザクションを実行する必要があるプロジェクトを開始しています。トランザクションについての基本的なことについての応答やリンクも歓迎します。


以下は、開始として使用するcodeproject上の.NETトランザクションの良い例です。
ミッチェルセラーズ

回答:


271

トランザクションには主に2種類あります。接続トランザクションとアンビエントトランザクション。接続トランザクション(SqlTransactionなど)は、db接続(SqlConnectionなど)に直接関連付けられています。つまり、接続の受け渡しを継続する必要があります-場合によってはOKですが、「作成/使用/解放」は許可されません。使用、およびクロスDB作業を許可しません。例(スペース用にフォーマット済み):

using (IDbTransaction tran = conn.BeginTransaction()) {
    try {
        // your code
        tran.Commit();
    }  catch {
        tran.Rollback();
        throw;
    }
}

面倒すぎず、接続「conn」に限定されています。別のメソッドを呼び出す場合は、「conn」を渡す必要があります。

代替は、アンビエントトランザクションです。.NET 2.0の新機能であるTransactionScopeオブジェクト(System.Transactions.dll)では、さまざまな操作を使用できます(適切なプロバイダーがアンビエントトランザクションに自動的に参加します)。これにより、既存の(非トランザクション)コードに簡単にレトロフィットしたり、複数のプロバイダーと話したりすることができます(ただし、複数のプロバイダーと話すとDTCが関与します)。

例えば:

using(TransactionScope tran = new TransactionScope()) {
    CallAMethodThatDoesSomeWork();
    CallAMethodThatDoesSomeMoreWork();
    tran.Complete();
}

ここで、2つのメソッドは独自の接続(open / use / close / dispose)を処理できますが、何も渡さなくても暗黙的にアンビエントトランザクションの一部になることに注意してください。

コードにエラーがある場合、Dispose()はComplete()なしで呼び出されるため、ロールバックされます。予想されるネストなどがサポートされていますが、内部トランザクションをロールバックすることはできませんが、外部トランザクションは完了します。誰かが不満を持っている場合、トランザクションは中止されます。

TransactionScopeのもう1つの利点は、データベースだけに関連付けられていないことです。トランザクション対応プロバイダーは、それを使用できます。たとえば、WCF。あるいは、TransactionScope互換のオブジェクトモデルもいくつかあります(つまり、ロールバック機能を備えた.NETクラス-おそらく私はこの方法を使用したことがありませんが、記念品より簡単です)。

全体として、非常に便利なオブジェクトです。

いくつかの警告:

  • SQL Server 2000では、TransactionScopeはすぐにDTCに移動します。これはSQL Server 2005以降で修正されており、DTCに昇格したときに2つのソースなどと通信するまでLTM(オーバーヘッドがはるかに少ない)を使用できます。
  • 接続文字列を微調整する必要があることを意味するグリッチがあります

CSLA .NET 2.0はTransactionScopeオブジェクトをサポートしています!
Binoj Antony

ここでの問題は、最初のメソッドにトランザクションがあり、このメソッド(カプセル化)が親トランザクションから呼び出されるかどうかを知らない場合です。
Eduardo Molteni 2009年

1
@Eduardo-TransactionScopeを使用する場合は問題ではないため、非常に魅力的です。このようなトランザクションはネストされ、最も外側のコミットのみがコミットします。
Marc Gravell

あなたがまだ聞いていることを望みます。「周りにTransactionScope互換のオブジェクトモデルがいくつかある」とおっしゃいました。それらのいくつかを教えてもらえますか?どうも。
majkinetor 2009

1
再びマーク、別の優れた説明。「期待されるネストがサポートされている」と言ったのは、メソッド(たとえば、CallAMethodThatDoesSomeWork())内で定義されたトランザクションブロック自体ですか?または、transactionscopeが外部で定義されている場合、それは必要ありませんか?
Phil Cooper

11
protected void Button1_Click(object sender, EventArgs e)
   {


       using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True"))
       {
           connection1.Open();

           // Start a local transaction.
           SqlTransaction sqlTran = connection1.BeginTransaction();

           // Enlist a command in the current transaction.
           SqlCommand command = connection1.CreateCommand();
           command.Transaction = sqlTran;

           try
           {
               // Execute two separate commands.
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('a','b','c')";
               command.ExecuteNonQuery();
               command.CommandText =
                "insert into [doctor](drname,drspecialization,drday) values ('x','y','z')";
               command.ExecuteNonQuery();

               // Commit the transaction.
               sqlTran.Commit();
               Label3.Text = "Both records were written to database.";
           }
           catch (Exception ex)
           {
               // Handle the exception if the transaction fails to commit.
               Label4.Text = ex.Message;


               try
               {
                   // Attempt to roll back the transaction.
                   sqlTran.Rollback();
               }
               catch (Exception exRollback)
               {
                   // Throws an InvalidOperationException if the connection 
                   // is closed or the transaction has already been rolled 
                   // back on the server.
                   Label5.Text = exRollback.Message;

               }
           }
       }


   }

4

C#自体でトランザクションを実行する代わりに、トランザクションを独自のストアドプロシージャにラップして、そのように処理することもできます。



0

また、必要なものによっても異なります。基本的なSQLトランザクションの場合、コードでBEGIN TRANSとCOMMIT TRANSを使用してTSQLトランザクションを試すことができます。これが最も簡単な方法ですが、複雑なため、適切にコミット(およびロールバック)するように注意する必要があります。

私は次のようなものを使用します

SQLTransaction trans = null;
using(trans = new SqlTransaction)
{
    ...
    Do SQL stuff here passing my trans into my various SQL executers
    ...
    trans.Commit  // May not be quite right
}

障害が発生すると、エラーが発生usingし、トランザクションは常にコミットまたはロールバックされます(実行する指示に応じて異なります)。私たちが直面した最大の問題は、常にコミットすることでした。を使用すると、トランザクションの範囲が制限されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.