2009-04-06 244 views
14

TransactionScopeを使用する際に問題があります。 TransactionScopeは、データアクセスレイヤー全体でトランザクションを使用できる非常に優れた柔軟性を得ています。このようにして、暗黙的または明示的なトランザクションを使用できます。もう一度ADO.NETトランザクションのパフォーマンスが向上しますが、現時点ではこれは実際問題ではありません。しかし、私たちはロックに問題があります。下のサンプルコードでは、分離レベルはReadCommittedに設定されていますが、テーブル全体をロックしているため、(Mainメソッドの)メイントランザクションがコミットされるまで、testTableの他のクライアントからSelect SQLステートメントを作成することはできません。また、すべてのメソッドで1つの接続だけを使用しようとしましたが、同じ動作です。私たちのDBMSはSQL Server 2008です。私たちが理解できなかったことがありますか?TransactionScopeと分離レベル

よろしく アントンKalcik

このサンプルコードを参照してください:

class Program 
{ 
    public class DAL 
    { 
     private const string _connectionString = @"Data Source=localhost\fsdf;Initial Catalog=fasdfsa;Integrated Security=SSPI;"; 

     private const string inserttStr = @"INSERT INTO dbo.testTable (test) VALUES(@test);"; 

     /// <summary> 
     /// Execute command on DBMS. 
     /// </summary> 
     /// <param name="command">Command to execute.</param> 
     private void ExecuteNonQuery(IDbCommand command) 
     { 
      if (command == null) 
       throw new ArgumentNullException("Parameter 'command' can't be null!"); 

      using (IDbConnection connection = new SqlConnection(_connectionString)) 
      { 
       command.Connection = connection; 
       connection.Open(); 
       command.ExecuteNonQuery(); 
      } 
     } 

     public void FirstMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello1")); 

      using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       ExecuteNonQuery(command); 
       sc.Complete(); 
      } 
     } 

     public void SecondMethod() 
     { 
      IDbCommand command = new SqlCommand(inserttStr); 
      command.Parameters.Add(new SqlParameter("@test", "Hello2")); 

      using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       ExecuteNonQuery(command); 
       sc.Complete(); 
      } 
     } 
    } 

    static void Main(string[] args) 
    { 

     DAL dal = new DAL(); 
     TransactionOptions tso = new TransactionOptions(); 
     tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; 

     using (TransactionScope sc = new TransactionScope(TransactionScopeOption.Required,tso)) 
     { 
      dal.FirstMethod(); 
      dal.SecondMethod(); 
      sc.Complete(); 
     } 
    } 
} 

答えて

19

を私はあなたの問題は、.NETのTransactionScopeのコンセプトとは何かを持っているとは思いません。むしろ、SQL Serverトランザクションの予想される動作を説明しているようです。また、分離レベルを変更するだけでは、「データ書き込み」ではなく「データ読み取り」に影響します。 SQL ServerのBOLから:

「トランザクション分離レベルは、データの変更を保護するために取得したロックに影響を与えることはありません選択して、トランザクションは常に、それが修飾する任意のデータに排他ロックを取得し、トランザクションが完了するまでそのロックを保持しています。そのトランザクションに設定された独立性レベルに関係なく、トランザクション分離レベルは、主に他のトランザクションによる変更の影響から保護レベルを定義します。その手段は、あなたがSELECTの文(複数可)を発行したクライアントのための分離レベルを変更することにより、ブロッキング動作を防ぐことができるということです何

READ COMMITED分離レベル(デフォルト)はブロックを防ぎません。クライアントをブロックしないようにするには、READ UNCOMMITTED分離レベルを使用しますが、開いているトランザクションによって更新/挿入されたレコードを取り出す可能性があることを考慮する必要があります(トランザクションがロールバックされると消滅する可能性があります) 。

+0

あなたのヒントをありがとう。したがって、トランザクションスコープのトランザクション分離レベルの設定は、このトランザクションスコープからDBMSの読み取り操作によってデータにアクセスする方法にのみ影響します。 –

9

取引についてお話するのに良い質問です。

主な方法は、トランザクションをコミットすることです。他のメソッド内でコミットしても、その行にはまだロックがあります。 READ COMMITTEDを使用してそのテーブルを読み取ることはできません。これは、ロックトランザクションをコミットするまで予想されます。

は、ここで最初のメソッドの復帰後です:

First method returns

第二の方法戻った後、あなたがテーブルに1つの以上のロックを追加します。

secont method returns

我々はSPID(55)と、クエリウィンドウからSELECT文を実行する場合は、状況を待って表示されます。あなたのmainメソッドトランスコミットした後

select is waiting

、あなたはselect文の結果を取得し、それが唯一のが私たちのselect文クエリページからロックを共有表示されます。X

Scope commits and select returns

排他的ロック、IX意図的ロックを意味します。 You can read more from my blog post about transactions

待たずに読みたい場合は、nolockヒントを使用できます。最初のメソッドがコミットした後に読み込みたい場合は、その外側のスコープを削除することができます。

関連する問題