2012-08-13 76 views
0

由於代碼重構而出現問題,在這種情況下最好的解決方案是什麼?製作可變線程安全的最佳方式是什麼?

問題是DbConnection從本地方法變量重構爲類變量。 該應用程序是多線程的。 看來問題在於當它是一個成員變量時,DbConnection對象被共享。 什麼是最佳解決方案?把它當作本地方法變得可變?

public IDataReader Execute(CommandBehavior behavior, string[] parameterNames, object[] arguments) 
{ 

     DbConnection conn = null; 
     try 
     { 

      conn = Connection.CreateConnection(); 

      DbCommand cmd = conn.CreateCommand(); 
      cmd.CommandText = StoredProcedureName; 
      cmd.CommandType = CommandType.StoredProcedure; 



      //  .................................................. 

      // Perform the call.       
      return DataCachingContext.SetCachedData(call, cmd.ExecuteReader(behavior)); 

     } 
     catch (Exception ex) 
     { 
      //.......................... 
     } 
     finally 
     { 
      // 
     } 

} 

只是爲了澄清,這裏是導致問題的版本。帶有運行時異常,與ResultSet的索引有關,這很可能是由於連接被覆蓋。

DbConnection _conn = null; 

public IDataReader Execute(CommandBehavior behavior, string[] parameterNames, object[] arguments) 
{ 

     try 
     { 

      _conn = Connection.CreateConnection(); 

      DbCommand cmd = _conn.CreateCommand(); 
      cmd.CommandText = StoredProcedureName; 
      cmd.CommandType = CommandType.StoredProcedure; 



      //  .................................................. 

      // Perform the call.       
      return DataCachingContext.SetCachedData(call, cmd.ExecuteReader(behavior)); 

     } 
     catch (Exception ex) 
     { 
      //.......................... 
     } 
     finally 
     { 
      // 
     } 

} 

經過更多的調查後,它看起來像DbConnection變量是一個類變量啓用單元測試。當它是一個局部變量時,沒有辦法測試它的價值。 DbConnection的狀態正在測試中

+4

最好的方法是研究[標籤:線程安全]和[標籤:多線程]。這個問題在這裏被問了數百次;可能已經被問過_today_。 – 2012-08-13 14:53:42

+1

我在這裏沒有看到任何問題,除了你說DbConnection是一個類變量,在這裏它顯然是一個局部變量,你有兩次聲明嗎?如果這不是問題,我們需要更多細節。 – crlanglois 2012-08-13 14:55:56

+0

我在代碼中看不到任何線程。 DataCachingContext是共享對象嗎?它是「靜態」嗎? – 2012-08-13 14:59:08

回答

1

該應用程序是多線程的。看來問題在於當它是一個成員變量時,DbConnection對象被共享。什麼是最好的解決方案?把它當作本地方法變得可變?

是的,使用DbConnection的良好模式是在方法中創建和配置連接(將其存儲在本地變量中)。在幕後,連接被彙集起來,所以沒有像這樣做的重大開銷。您還可以避免必須處理共享狀態和鎖定。

問題中提供的代碼與我在這裏描述的完全一致。

+0

經過更多的調查後,它看起來像DbConnection變量是一個類變量,以啓用單元測試。當它是一個局部變量時,沒有辦法測試它的價值。 DbConnection的狀態正在測試中。 – learnerplates 2012-08-13 15:41:45

+0

其實你可以實現並傳遞'DbProviderFactory'到你的類爲了產生單元測試的模擬連接:http://msdn.microsoft.com/en-us/library/ms971499.aspx – 2012-08-13 15:54:18

+0

木瀆,我不瞭解這個。你可以解釋嗎?現在我正在尋找類變量的替代方案,以便我可以從單元測試中測試DbConnection的狀態。有一些方法可以從一些全球存儲獲得連接嗎?然後測試它的狀態。 – learnerplates 2012-08-14 12:03:17

4

我認爲您正在尋找lock statement

鎖確保一個線程不會進入代碼的關鍵部分,而另一個線程處於關鍵部分。如果另一個線程試圖輸入一個鎖定的代碼,它將等待,阻止,直到該對象被釋放。

+0

只要確保處理好您的異常以避免不釋放該對象。 – 2012-08-13 14:59:54

+4

@Andre不需要。使用'lock'自動處理 - 實際上,這就是使用'lock'而不是'Monitor.Enter'的全部要點。 – 2012-08-13 15:01:27

+0

@KonradRudolph如果'using'塊內發生異常,對象是否仍然被釋放? – 2012-08-13 16:51:40

1

數據庫連接對象通常應該是局部變量,因爲數據庫連接是一個相對昂貴的資源,可以在任何時間段內保持打開狀態。將數據庫連接作爲類變量的危險在於連接將在對象實例化時打開,然後將保持打開狀態,直到類被丟棄。這可能導致鎖不能及時釋放,長時間運行的事務會嚴重影響性能。

在需要之前打開連接(例如,調用存儲過程,執行SQL語句)並在之後立即關閉/處置它會好得多。在封面之下,數據庫連接通常都會緩存,這樣可以最大限度地減少重複打開和關閉連接的開銷,因爲當您在代碼中打開連接時,您將有可能從緩存中獲得已打開的連接。

1

MSDN文檔上說DbConnection

所有實例成員不能保證線程安全的。

因此,在我看來,將它作爲類變量並不是一個好主意。即使您的實現可能是線程安全的,假設如此,也是有風險的。您可以使用鎖來避免線程問題,但這些方法通常會嚴重縮放。所以,最好將對象保留在本地。

如果你擔心的情況下,過多的連接打開和關閉所有的時間表現,看看SQL Server Connection Pooling (ADO.NET)這確實相當不錯池實際連接,而不是DbConnection對象。

0

在這兩個代碼片段中都可以創建新的連接。那麼連接類變量的意圖是什麼?從你發佈的代碼看來,連接應該是局部變量。

相關問題