エラーの「無効な操作、接続が閉じられた」ことからTransactionのTimeoutタイムアウトメカニズムを探究する

7044 ワード

1、エラーは以下の通りです:Invalid Operation the connection is closed、無効な操作、接続が閉じられます.このエラーは、毎回報告されるわけではなく、複雑な操作や大きなトランザクションの場合にのみ偶然報告されます.
stackOverflowにはこの問題に関する議論がたくさんあります.例えば、《System.Data.OracleClient random Invalid Operation the connection is closed》ですが、ばらばらで、全部スキャンした後、私はまだ次のような疑問を持っています.
1)TransactionScopeのTimeoutがどれくらいなのか、例えばTransactionOptions.Timeout=new TimeSpan(0,0,3)が設定された後、TransactionScopeのタイムアウトが3 sであることをどうやって知ったのですか?
2)デフォルトのMaxTimeout=10 mでは、どのようにして任意の値を設定できますか?
3)ネストされたトランザクションの外部タイムアウトには、すべての内部トランザクションの時間が含まれていますか?
4)タイムアウトメカニズムはどのように機能しますか?
Reflectorなどのツールでソースコードをチェックして、やっと初歩的な理解ができて、間違っているところ、みんなに指摘してください!
 
2、TransactionScopeのTimeoutをどう思いますか.
デバッガを使用してTransactionScopeを段階的に展開する例は次のとおりです.
scope->committableTransaction->base->internalTransaction->absoluteTimeout // :      ,    

このabsoluteTimeoutは実際の結果ですが、設定した値と一致しないことがよくあります.たとえば、次のようにします.
TimeSpan
absoluteTimeout
3s
5
10s
19
1m
117
10m
1171
30m
3515
1h
7031
あるアルゴリズムによって変換された値のように見えますが、このアルゴリズムはTransactionTableに書かれています.TimeoutTicks()内:
internal long TimeoutTicks(TimeSpan timeout){

  if(timeout != TimeSpan.Zero) {

    return (timeout.Ticks / 10000L >> 9) + this.ticks;

  } 

  return 9223372036854775807L;

}

これで分かります.上の対照表を加えると、absoluteTimeoutで設定が有効かどうかを知ることができます.
 
3、デフォルトのMaxTimeout=10 mでは、どのようにして任意の値を設定できますか?
1)まずこの10 mはどうやって来たのかを話しましょう.
TransactionScope.ctr()->TransactionManager.ValidateTimeout()->MaximumTimeout->MachineSettingsSection.MaximumTimeout

この属性はまずc:windowsMicrosoftを読みます.NET\Framework\v4.0.30319\Config\machine.configの値://対応するframeworkのバージョンに注意!
<system.transactions>

  <machineSettings maxTimeout="00:10:00" />

</system.transactions>

もちろん、すべてのバージョンのmachineを見てみます.configにはデフォルトでこのノードはありません.では、一歩下がって、Attributeでデフォルト値を設定します.
[ConfigurationProperty("maxTimeout", DefaultValue = "00:10:00")]

public TimeSpan MaxTimeout

 
2)どうやって任意の値に変更しますか?
2.1)machine.config、利点:便利、欠点:機械上のすべての事務に影響します.方法はグローバルなmachineです.configに対応ノードを追加し、自分のapp/webに注意する.configにノードを追加するとエラーが表示されます.
2.2)反射(神器)!利点:自分のトランザクションにのみ作用し、欠点:反射、やや面倒、やや遅い.
static void ChangeMaximumTimeout() {

 Type t = typeof(TransactionManager);

 FieldInfo f = t.GetField("_cachedMaxTimeout", BindingFlags.NonPublic | BindingFlags.Static);

 f.SetValue(null, true);

 f = t.GetField("_maximumTimeout", BindingFlags.NonPublic | BindingFlags.Static);

 f.SetValue(null, new TimeSpan(2, 0, 0));

}

最終的にはstaticクラスのstatic属性を取っているからです.
public static class TransactionManager {

 public static TimeSpan MaximumTimeout {

  get {

   if(!_cachedMaxTimeout) {

     _maximumTimeout = MachineSettings.MaxTimeout;

   }

   return _maximumTimeout; }}}

貼って、一目瞭然!
 
4、ネストされたトランザクションの外部タイムアウトには、すべての内部トランザクションの時間が含まれていますか?
外層タイムアウトには、すべての内層トランザクションの実行時間が含まれていることを理解しています.テストコードは次のとおりです.
option.Timeout = new TimeSpan(0,0,3);

using(var scope = new TransactionScope(TransactionScopeOption.Required, option)) {

 Thread.Sleep(2000);



 option1.Timeout = new TimeSpan(0,0,5);

 using(var scope1 = new TransactionScope(TransactionScopeOption.Required, option)) {

  Thread.Sleep(500); // 800           

}}

 
5、タイムアウトメカニズムはどのように機能しますか?
1)非ルート(committableTransaction==null)トランザクションの場合、タイムアウトロールバックをトリガーするscopeTimer=new Timer(timeSpan,TimeoutCallback)が作成されます.
2)committableTransaction!=nullのルートトランザクション、タイムアウトメカニズムはまだ見つかっておらず、補完が必要です.