それは悪い習慣ではありません。覚えておくべきことの1つは、すべてのステートメントが暗黙のトランザクションを使用し、ステートメントが終了すると自動的にコミットすることです。つまり、(Fillで使用されるSELECTのように)SELECTは常にトランザクションを使用します。問題は、それ自体でトランザクションを開始する必要があるのか、既存のトランザクションを使用するのかということです。
暗黙的なトランザクションと明示的なトランザクションでSELECTによって取得されるロックの数、タイプ、および期間に違いはありますか?デフォルトのトランザクションモデル(READ COMMITTED分離)NOでは、何もありません。動作は同じで、区別できません。他の分離レベル(繰り返し可能な読み取り、シリアル化可能)では違いがありますが、それは目的のより高い分離レベルが発生するために必要な違いであり、必要に応じて、明示的なトランザクションを使用することがこの目的の分離レベルを達成する唯一の方法です。
さらに、あなたの例のように(生成されたIDを読み戻す)、SELECTが保留中の(まだコミットされていない)トランザクションの効果を読み取らなければならない場合、他の方法はありません。SELECTは、IDを生成したトランザクションの一部である必要があります。そうでない場合、コミットされていないIDを表示できません。
ただし、注意が必要です。このすべてのトランザクション処理をはるかに簡単にすることができる優れたツールであるSystem.Transactionsを自由に使用できると思います。すべてのADO.Netコードはシステムトランザクションに対応しており、単に。を宣言すると、接続とコマンドが保留中のトランザクションに自動的に登録されますTransactionScope
。つまり、関数FooがaTransactionScope
を宣言してから関数Barを呼び出す場合、BarがADO.Net操作を実行すると、Barが明示的に何もしなくても、自動的にFooで宣言されたトランザクションの一部になります。はTransactionScope
スレッドコンテキストにフックされ、Barによって呼び出されるすべてのADO.Net呼び出しは、このコンテキストを自動的にチェックして使用します。私は本当に何かを意味することに注意してください ADO.Net call, including Oracle provider ones. Alas though there is a warning: using new TransactionScope() Considered Harmful: the default constructor of TransactionScope
will create a serializable transaction, which is overkill. You have to use the constructor that takes a TransactionOptions
object and change the behavior to ReadCommitted. A second gotcha with TransactionScope
is that you have to be very careful how you manage connections: if you open more than one connection under a scope then they will be enrolled in a distributed transaction, which is slow and requires MSDTC to be configured, and leads to all sort of hard to debug errors. But overall I fell that the benefits of using TransactionScope
outweight the problems, and the resulted code is always more elegant than passing around IDbTransaction
explicitly.