2

を使用すると、これは、トランザクション・スコープを使用する正しい方法です:のTransactionScope複数回に

私は事の一部を表すオブジェクトを持っている:

public class ThingPart 
{ 
    private DbProviderFactory connectionFactory; 

    public void SavePart() 
    { 
     using (TransactionScope ts = new TransactionScope() 
     { 
      ///save the bits I want to be done in a single transaction 
      SavePartA(); 
      SavePartB(); 
      ts.Complete(); 
     } 
    } 

    private void SavePartA() 
    { 
     using (Connection con = connectionFactory.CreateConnection() 
     { 
      con.Open(); 
      Command command = con.CreateCommand(); 
      ... 
      command.ExecuteNonQuery();    
     } 
    } 

    private void SavePartB() 
    { 
     using (Connection con = connectionFactory.CreateConnection() 
     { 
      con.Open(); 
      Command command = con.CreateCommand(); 
      ... 
      command.ExecuteNonQuery();    
     } 
    } 
} 

と実物を表し何か:

public class Thing 
{ 
    private DbProviderFactory connectionFactory; 

    public void SaveThing() 
    { 
     using (TransactionScope ts = new TransactionScope() 
     { 
      ///save the bits I want to be done in a single transaction 
      SaveHeader(); 
      foreach (ThingPart part in parts) 
      { 
       part.SavePart(); 
      } 
      ts.Complete();  
     } 
    } 

    private void SaveHeader() 
    { 
     using (Connection con = connectionFactory.CreateConnection() 
     { 
      con.Open(); 
      Command command = con.CreateCommand(); 
      ... 
      command.ExecuteNonQuery();    
     } 
    } 
} 

私も多くのこと

public class ThingManager 
{  
    public void SaveThings 
    {   
     using (TransactionScope ts = new TransactionScope) 
     {    
      foreach (Thing thing in things) 
      { 
       thing.SaveThing(); 
      }    
     }   
    }  
} 
を管理して何かを持っています

その私のことを理解:接続は新しいことではないだろうと、プールからのたびに再利用されます

  • (DBPROVIDERと仮定すると、接続プーリングをサポートし、それが有効になっている)
  • 取引は、そのような場合ということになります私はちょうどThingPart.SavePart(他のクラスの文脈の外から)を呼び出した後、パートAとパートBの両方が保存されるかどちらも保存されません。
  • 私はすべての後、ThingManager.SaveThingsを呼び出すと、すべてが同じトランザクション
  • に起こるのだろうつまり、その後、ヘッダーとすべての部品がすべて保存されますか非となります(他のクラスのコンテキスト外から)Thing.Saveを呼び出す場合私のものは救われるでしょうし、そうでないものもあります。つまり、すべてが同じ取引で起こります。
  • 私が使用しているDbProviderFactory実装を変更した場合、それは違い

を行うべきではありません、私の仮定が正しいですか?

オブジェクトの構造や永続性の責任については何も無視します。これは私がどのようにしてやるべきかを理解する助けになる例です。私がSqlLiteをdbプロバイダ・ファクトリとして使ってoracleを置き換えようとすると、うまく動作しないように見えますが、私は調査の時間をどこに費やすべきか疑問に思っています。

答えて

3

あなたの弾丸を答える(と私は、Microsoft SQL Server 2005以降を想定してきました):

  1. の接続は、これが依存

    • 新しいプールから再利用されません - 例えばすべての接続が同じDBに対して、同じ資格情報で、SQLが軽量トランザクション・マネージャー(SQL 2005以降)を使用できる場合は、SAME接続は集約トランザクションの連続ステップで再利用されます。 (ただし、SQL接続プーリングは依然として機能していましたか?)
  2. アトミックSavePart - これはACIDが期待どおりに動作します。
  3. はい同じスコープの入れ子のTransactionScopesもアトミックです。トランザクションは、最も外側のTSが完了したときにのみコミットします。
  4. はい、アトミックですが、SQLロックをエスカレートすることに注意してください。個々のThing(およびThingParts)を個別にコミットすることが理にかなっている場合は、これはSQLの並行処理の観点からは望ましいことです。
  5. Providerは、TransactionScopeリソースマネージャ(おそらくDTC準拠)と互換性がある必要があります。例えばデータベースをRocket U2に移動してTransactionScopesが動作することを期待しないでください。

ちょうど1つのgotcha - new TransactionScope() defaults to isolation level READ_SERIALIZABLE - ほとんどのシナリオでは悲観的すぎることがよくあります。通常、READ COMMITTEDがより適用されます。

+0

関連:http://stackoverflow.com/a/22512547/314291 – StuartLC