2010-08-24 81 views
3

我正在爲C#設計數據庫包裝。 下面是兩個選擇,我有:C#數據庫包裝設計

選項A:

class DBWrapper:IDisposable 
{ 
    private SqlConnection sqlConn; 

    public DBWrapper() 
    { 
      sqlConn = new SqlConnection("my connection string"); 
      sqlConn.Open(); 
    } 

    public DataTable RunQuery(string Sql) 
    { 
       implementation...... 
    } 

    public Dispose() 
    { 
      if(sqlConn != null) 
        sqlConn.Close(); 
    } 
} 

選項B:

class DBWrapper 
{ 
    public DBWrapper() 
    {    
    } 

    public DataTable RunQuery(string Sql) 
    { 
      SqlConnection sqlConn = new SqlConnection("my connection string"); 
      .....implementation...... 
      sqlConn.Close();    
    } 
} 

對於選項時,類實例化打開的連接。因此,無論調用者調用RunQuery多少次,連接總是準備就緒。但是,如果應用程序在應用程序的早期初始化DBWrapper,則連接將會剛剛打開,在應用程序完成之前什麼也不做。另外,它可能會在執行過程中實例化許多DBWrapper。所以,這有點浪費資源。

對於選項B,它沒有A選項的問題選項,但每次調用者調用RunQuery時都必須打開和關閉一個新連接。我不確定這會對錶演造成多大的傷害。

請分享您的專業知識。謝謝你的閱讀。

+1

他們往往會在這裏得到一個壞名字,但有一個Singleton設計模式的閱讀,這是我唯一一次使用單身人士 – acqu13sce 2010-08-24 05:56:01

+0

@ acqu13sce:爲什麼壞名字?模擬能力的原因是什麼? – kbrimington 2010-08-24 06:00:29

+0

只是我通過閱讀包括這個社區維基閱讀一些評論http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons 我個人認爲他們有他們的位置,但也許做被過度使用 – acqu13sce 2010-08-24 06:11:16

回答

6

出於性能考慮,你一定不希望與選項B去 讓我建議選擇C(至少在我所經歷的情況。):

class DBWrapper:IDisposable { private SqlConnection sqlConn; 

public void EnsureConnectionIsOpen() 
{ 
    if (sqlConn == null) 
    { 
     sqlConn = new SqlConnection("my connection string"); 
     sqlConn.Open(); 
    } 

} 

public DataTable RunQuery(string Sql) 
{ 
    EnsureConnectionIsOpen(); 
    implementation...... 
} 

public Dispose() 
{ 
    if(sqlConn != null) 
       sqlConn.Close(); 
} 

} 

您可以考慮使用Singleton模式以確保只有一個DBWrapper實例。

+1

請注意,使用單例模式時,您可能會遇到一些有關多線程的問題(如果實現模式不正確)。雖然單身人士通常是這種類型的代碼的良好解決方案,但在應用程序中使用靜態應用程序時,應始終保持警覺並檢查多線程問題。 – Gertjan 2010-08-24 06:03:33

+1

Singleton只是在線程之間共享對象的一種方式,但顯然,只要您在線程之間共享對象,就必須仔細設計多線程,無論它們如何共享。 – Philipp 2010-08-24 06:08:42

+0

如果您在線程之間共享數據庫連接(並且在用戶之間的Web場景中),則可能會出現「有趣」的情況。它也將禁用你有多個連接。在父 - 子關係中收集數據時,有時需要多個連接,在這種情況下,當第一個連接用於收集父母時,您打開第二個連接以獲取子項。 – Gertjan 2010-08-24 06:13:05

2

值得考慮的幾點意見:

在你管理一個(也許)長期連接的方法,它來檢查連接是否運行查詢之前開放是非常重要的。一段時間之後,我遇到了.NETCF關閉未使用的連接之前的問題。

在您爲每個查詢打開一個新連接的方法中,確保您的連接,命令和(如果使用)數據讀取器都使用語句正確包裝或嘗試/ finally + dispose()塊以釋放連接和鎖。

快樂編碼!

+0

謝謝您的提醒。 對於選項A,如果我確保我的類沒有公開任何關閉連接的函數,並且總是有一個構造函數打開連接,那麼應該沒問題吧? 雅,我使用「使用」語句。 – Dreteh 2010-08-24 06:51:24

+0

@dreteh:我建議在使用前提供一個私人/受保護的財產來檢查連接。類似'protected SqlConnection Connection {get {if(sqlConn.State == ConnectionState.Closed)sqlConn.Open();返回sqlConn; }}。作爲一個免責聲明,我從來沒有遇到框架在緊湊框架之外關閉連接的問題。也許這個建議對於一個完整框架的應用程序來說是過分的。我會很好奇,看看連接是否會自動關閉進入待機或休眠狀態的筆記本電腦。 – kbrimington 2010-08-24 11:12:41

1

選項B更具交易性,這是它的優勢。 ADO.NET使用隱式連接池,因此您不必擔心頻繁創建SqlConnection的新實例。

您應該考慮是否使用連接或斷開的數據模型;因爲第二種方法更適合斷開連接的模型。

但正如我上面所說的,連接池意味着它在實際應用上幾乎沒有區別。

+0

您的回答非常有用。 我正在考慮選項B,因爲我想重載需要額外連接對象的RunQeury函數,這樣我可以將幾個數據訪問器分組來實現事務(這樣它們可以共享相同的連接)。我真正關心的唯一事情是不斷打開和關閉連接可能效率不高。 – Dreteh 2010-08-24 07:02:20

0

您可以有一個選項C,其中數據庫在RunQuery中請求時打開(如果未打開),並在處置(打開時)時關閉。這樣數據庫只在真正需要時纔打開,並且只會打開一次。

因此,在僞代碼:

class DBWrapper 
{ 

    public DBWrapper() 
    {    
    } 

    SqlConnection sqlConn = null; 

    public DataTable RunQuery(string Sql) 
    { 
      if(sqlConn == null) sqlConn = new SqlConnection("my connection string"); 
      .....implementation......    
    } 
    public Dispose() 
    { 
      if(sqlConn != null) 
        sqlConn.Close(); 
    } 

} 

而且記住,時刻調用Dispose並不總是直接後不需要再對象(例如一個函數變量使用該函數後)。據我所知,當垃圾收集器收集對象時(這不是直接的),它會被執行。但我對此並不完全確定。 Web和非Web應用程序之間的行爲也可能不同。

+0

但是我可以看到這個設計也會有OptionA的問題,因爲想象一下,如果RunQuery在執行開始時被調用,並且不會再被使用,直到結束。 – Dreteh 2010-08-24 06:54:36

+0

這是真的,但連接將在第一次需要時打開,而示例A在構建對象時打開。如果您希望收緊數據庫的生命週期,則應手動關閉它,因爲系統無法猜測您將來是否以及何時可能需要該數據庫。 – Gertjan 2010-08-24 07:09:43

2

垃圾收集器在相當複雜的條件下被觸發,但基本上當內存超過某個限制時被調用,它也被週期性地調用,但週期不是恆定的。你永遠無法確定垃圾收集器的確切時間,並因此(在另一次運行中)破壞對象。有一件事你可以肯定的是,垃圾收集器永遠不會處置和銷燬仍然有引用的對象。例如,通過類上的靜態變量引用的對象既不會被丟棄也不會被銷燬。