2010-10-24 66 views
3

我需要一些關於我寫的應用程序的建議。我遇到的問題是由於我的DAL和連接到我的SQL Server 2008數據庫沒有關閉,但是我查看了我的代碼,並且每個連接總是被關閉。C#多線程應用程序和SQL連接幫助

該應用程序是一個多線程應用程序,用於檢索一組記錄,並在處理記錄時更新有關記錄的信息。

這裏是流量:

的管理員可以設置運行的線程數量拉動能力和多少條記錄每個線程。

這裏是運行他們點擊開始後的代碼:

適配器是抽象的在這裏我DAL是他們看起來像一個示例:

public class UserDetailsAdapter: IDataAdapter<UserDetails> 
{ 
    private IUserDetailFactory _factory; 

     public UserDetailsAdapter() 
     { 
      _factory = new CampaignFactory(); 
     } 

     public UserDetails FindById(int id){ 
      return _factory.FindById(id); 
     } 
} 

只要_factory把它叫做處理SQL並立即關閉連接。

代碼爲線程應用程序:

private int _recordsPerthread; 


private int _threadCount; 

    public void RunDetails() 
    { 
     //create an adapter instance that is an abstration 
     //of the data factory layer 
     var adapter = new UserDetailsAdapter(); 

     for (var i = 1; i <= _threadCount; i++) 
     { 
      //This adater makes a call tot he databse to pull X amount of records and 
      //set a lock filed so the next set of records that are pulled are differnt. 
      var details = adapter.FindTopDetailsInQueue(_recordsPerthread); 
      if (details != null) 
      { 
       var parameters = new ArrayList {i, details}; 
       ThreadPool.QueueUserWorkItem(ThreadWorker, parameters); 
      } 
      else 
      { 
       break; 
      } 
     } 
    } 

    private void ThreadWorker(object parametersList) 
    { 
     var parms = (ArrayList) parametersList; 
     var threadCount = (int) parms[0]; 
     var details = (List<UserDetails>) parms[1]; 
     var adapter = new DetailsAdapter(); 


     //we keep running until there are no records left inthe Database 
     while (!_noRecordsInPool) 
     { 
      foreach (var detail in details) 
      { 
       var userAdapter = new UserAdapter(); 
       var domainAdapter = new DomainAdapter(); 

       var user = userAdapter.FindById(detail.UserId); 
       var domain = domainAdapter.FindById(detail.DomainId); 

       //...do some work here...... 

       adapter.Update(detail); 
      } 

      if (!_noRecordsInPool) 
      { 
       details = adapter.FindTopDetailsInQueue(_recordsPerthread); 


       if (details == null || details.Count <= 0) 
       { 
        _noRecordsInPool = true; 
        break; 
       } 
      } 
     } 
    } 

應用崩潰,因爲似乎有連接問題的數據庫。看我的日誌文件的DAL我看到這個:

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached

當我在一個線程運行它工作正常。我猜測,當我在多個線程中使用他時,我顯然與DB建立了太多的連接。關於如何在多個線程中保持這種運行的任何想法,並確保數據庫不會給我任何錯誤。

更新: 我想我的問題可能是我的數據庫中的死鎖。這裏是運行在SQL代碼WHE我得到一個死鎖錯誤:

WITH cte AS ( 
    SELECT TOP (@topCount) * 
    FROM 
    dbo.UserDetails WITH (READPAST) 
WHERE 
    dbo.UserDetails where IsLocked = 0) 

UPDATE cte 
    SET 
    IsLocked = 1 

    OUTPUT INSERTED.*; 

我以前從來沒有過與此代碼的問題(在其他應用程序)。我重新整理了我的索引,因爲它們99%是分散的。這沒有幫助。我在這裏不知所措。

回答

0

那麼,在做了一些研究之後,我發現SQL Server 2008中可能存在一個bug並且運行並行查詢。我得找,我發現這個討論的鏈接,但我結束了我的服務器上運行此:

sp_configure 'max degree of parallelism', 1; GO RECONFIGURE WITH OVERRIDE; GO

這會降低你的服務器的性能,整體,所以它可能不會是一些人的選擇,但它對我很好。

對於某些查詢,我添加了MAXDOP(n)(n是要使用的處理器的數量)選項,以便它們可以更高效地運行。它確實有點幫助。 其次,我發現我的DAL的Dispose方法使用GC.Suppressfinalize方法。所以,我最後的部分沒有正確地開啓我的DAL並且沒有關閉我的連接。 感謝所有參與者!

3

我對你的代碼連接在哪裏打開感到困惑,但你可能希望你的數據適配器實現IDispose(確保在離開using作用域時關閉池連接)並將代碼包裝在using塊中:

using (adapter = new UserDetailsAdapter()) 
{ 
    for (var i = 1; i <= _threadCount; i++) 
    { 
     [..] 
    } 
} // adapter leaves scope here; connection is implicitly marked as no longer necessary 

ADO.NET使用連接池,所以不需要(並且它可能會產生相反的效果)明確地打開和關閉連接。

+0

這是一個好主意...... – DDiVita 2010-10-24 13:52:09

+0

調用'.Close()'實際上並不會在使用池時關閉連接。調用'.Dispose()'也不會關閉連接。通過調用'.Close()'或'.Dispose()',將連接釋放到池中。(如果在處理之前未調用,則.Dispose()將調用'.Close()')。總是調用'.Dispose()'(最好使用using語句),並且如果花哨的話可以選擇調用'.Close()'。 – Mark 2010-10-25 21:44:10

+0

這就是我所說的「不需要明確地關閉它們」(我不知道'.Close()* * still *不會明確地關閉它們)。 'using'塊在處理完作用域後會處理'.Dispose()',並且DataAdapter需要隱式打開。 – 2010-10-26 05:01:39

0

我不清楚你是如何實際連接到數據庫的。適配器必須引用連接。

你如何實際初始化該連接?

如果您爲每個線程使用新的適配器,則必須爲每個適配器使用新的連接。

我對你的環境不太熟悉,但是我確信在你的數據庫開始抱怨之前你確實需要很多開放的連接!

+0

適配器只是我工廠圖層的抽象。工廠爲每個電話打開一個連接線,完成工作,然後關閉連接。所以每個調用都可能會打開一個新的數據庫連接。 – DDiVita 2010-10-24 14:15:33