2010-05-10 71 views
0

我的應用程序需要用戶登錄並允許他們編輯事物列表。但是,似乎如果同一用戶總是登出並編輯列表,則此用戶將遇到「System.Data.SqlClient.SqlException:Timeout過期」。錯誤。我讀過關於它可能由未提交的交易引起的評論。我有一個應用程序。SQL Server中可能的連接泄漏導致「System.Data.SqlClient.SqlException:超時過期」錯誤?

我將提供我正在使用的代碼,並且在那裏有一個IF語句,我有點擔心,但這似乎是一個合理的事情。

我只是想了解一下這裏發生了什麼,還有一個要更新或添加到數據庫中的對象列表。在應用程序中創建的新對象的ID爲0,而現有對象具有從DB生成的其自己的ID。如果用戶選擇刪除某些對象,則其ID將存儲在一個單獨的整數列表中。一旦用戶準備好保存更改,這兩個列表就會被傳遞到這個方法中。通過使用IF語句,添加ID爲0的對象(使用添加存儲過程),並更新具有非零ID的對象(使用更新存儲過程)。畢竟,FOR循環遍歷「刪除」列表中的所有整數,並使用刪除存儲過程刪除它們。所有這些都使用交易。

Public Shared Sub UpdateSomethings(ByVal SomethingList As List(Of Something), ByVal RemovalList As List(Of Integer)) 
Using DBConnection As New SqlConnection(conn) 
    DBConnection.Open() 
    Dim MyTransaction As SqlTransaction 
    MyTransaction = DBConnection.BeginTransaction() 
    Try 
     Using MyCommand As New SqlCommand() 
      MyCommand.Transaction = MyTransaction 
      MyCommand.CommandType = CommandType.StoredProcedure 

      For Each SomethingItem As Something In SomethingList 
       MyCommand.Connection = DBConnection 
       If SomethingItem.ID > 0 Then 
        MyCommand.CommandText = "UpdateSomething" 
       Else 
        MyCommand.CommandText = "AddSomething" 
       End If 
       MyCommand.Parameters.Clear() 
       With MyCommand.Parameters 
        If MyCommand.CommandText = "UpdateSomething" Then 
         .Add("@id", SqlDbType.Int).Value = SomethingItem.ID 
        End If 
        .Add("@stuff", SqlDbType.Varchar).Value = SomethingItem.Stuff 
       End With 
       MyCommand.ExecuteNonQuery() 
      Next 

      MyCommand.CommandText = "DeleteSomething" 
      For Each ID As Integer In RemovalList 
       MyCommand.Parameters.Clear() 
       With MyCommand.Parameters 
        .Add("@id", SqlDbType.Int).Value = ID 
       End With 
       MyCommand.ExecuteNonQuery() 

      Next 
     End Using 
     MyTransaction.Commit() 
    Catch ex As Exception 
     MyTransaction.Rollback() 
     'Exception handling goes here ' 
    End Try 

End Using 
End Sub 

這裏使用了三個存儲過程以及一些循環,所以我可以看到如果列表足夠大,如何將所有東西都保存起來。

我正在使用Visual Studio 2008進行調試,並且正在爲數據庫使用SQL Server 2000。

編輯:我似乎仍然得到這個錯誤。我甚至刪除了整個交易的事情,我仍然遇到它。此時,我假設這裏發生了某種泄漏。我試過不使用USING語句,並明確告訴命令和連接要自己處理,但沒有骰子。如果在短時間內調用這種方法,SQL Server的內存使用量也會增加很多。

我讀過增加SQLCommand的CommandTimeout屬性會有所幫助。我想知道這樣做是否有任何重大缺點或後果。

+0

順便說一句,我認爲你應該在catch子句中回滾後添加'Rethrow'。你實際上沒有處理異常,所以你應該允許它傳播。 – 2010-05-10 18:32:14

+0

我必須意外刪除了我發佈的示例中的異常處理,但感謝您指出。 :) – Michael 2010-05-10 19:10:53

回答

1

我相信我已經設法解決了這個問題。我修改了應用程序,以避免不必要的對數據庫的調用(即未更改對象不需要再次更新)並增加了SQLCommand對象的CommandTimeout屬性。到目前爲止,沒有問題。

非常感謝您的建議。

1

我會建議使用以下方式,那樣將永遠調用Dispose,並在每個未提交的情況下進行回滾。

using (SqlConnection sqlCn = new SqlConnection()) 
{ 
    using (SqlTransaction myTrans = sqlCn.BeginTransaction()) 
    { 
    ... 
    myTrans.Commit(); 
    } 
} 

此外,我不相信你需要爲每個執行一個新的SqlCommand。只需保持同一個並更新CommandText和參數。

+0

感謝您的建議。我會看看這是否能解決問題,因爲這是有道理的。 – Michael 2010-05-10 18:54:46

1

如果您有大量的命令,您可能希望在打開連接之前構建它們。在您開始交易並打開連接之後,轉入並執行它們。

你可能想使用的TransactionScope

Using _tx as New System.Transactions.TransactionScope(<add your own timeout here>) 

'Do all your sql work' 

If _noErrors Then 
    _tx.Complete() 
End If 

End Using 

與交易的範圍,你可以設置最多20分鐘的超時,而無需修改服務器設置。

+0

是否有這麼多時間增加超時時間的缺點?會影響性能嗎? – Michael 2010-05-11 18:02:55

+0

是的。對於任何事務,其開放時間越長,其使用的資源越被其他進程阻塞的時間越長。通常對於數據庫,您希望儘可能少地使用開放連接(因此首先創建所有命令對象)。還有其他方法可以對SQL進行批處理(Ms企業庫數據 - http://msdn.microsoft.com/zh-cn/library/ff380164(v=PandP.31).aspx),這可能對您更好。 – StingyJack 2010-05-12 12:14:37

相關問題