可能的连接泄漏导致SQL Server中出现“System.Data.SqlClient.SqlException:Timeout expired”错误?

时间:2010-05-10 18:26:17

标签: vb.net transactions sql-server-2000 timeout

我的应用程序要求用户登录并允许他们编辑事物列表。但是,似乎如果同一用户始终登录和注销并编辑列表,则此用户将遇到“System.Data.SqlClient.SqlException:Timeout expired”。错误。我已经阅读了有关它可能由未提交的交易引起的评论。我确实有一个进入应用程序。

我将提供我正在使用的代码,并且在那里有一个IF声明,我有点不确定,但这似乎是一件合理的事情。

我将继续讨论这里发生的事情,有一个要更新或添加到数据库中的对象列表。在应用程序中创建的新对象的ID为0,而现有对象具有从DB生成的自己的ID。如果用户选择删除某些对象,则其ID将存储在单独的整数列表中。用户准备好保存更改后,会将这两个列表传递给此方法。通过使用IF语句,添加ID为0的对象(使用Add存储过程),并更新具有非零ID的对象(使用Update存储过程)。毕竟,FOR循环遍历“删除”列表中的所有整数,并使用Delete存储过程删除它们。交易用于所有这些。

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属性会有所帮助。我想知道这样做是否有任何重大缺点或后果。

3 个答案:

答案 0 :(得分:1)

我建议使用以下内容,这样Dispose将始终被调用,并且在每个非承诺的情况下都是Rolledback。

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

另外,我不认为你需要为每次执行创建一个新的SqlCommand。只需保持相同并更新CommandText和Parameters。

答案 1 :(得分: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分钟。

答案 2 :(得分:1)

我相信我已成功解决了这个问题。我修改了应用程序,以便不会对数据库进行不必要的调用(即不需要再次更新未更改的对象),并增加了SQLCommand对象的CommandTimeout属性。到目前为止,没有问题。

非常感谢您的建议。