從報錯“無效操作,連接被關閉”探究Transaction的Timeout超時機制


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里的超時就是3s?

2)默認MaxTimeout=10m,怎么才能設置任意值?

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=10m,怎么才能設置任意值?

1)先說一下這個10m怎么來的?

TransactionScope.ctr()->TransactionManager.ValidateTimeout()->MaximumTimeout->MachineSettingsSection.MaximumTimeout

這個屬性先讀取c:\windows\Microsoft.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里添加<machineSettings>節點會報錯。

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的根事務,超時機制尚未找到,有待補充完整。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM