这是我在DAL中的代码示例。对数据库存储过程的所有调用都是以这种方式构造的,并且没有内联SQL。
Friend Shared Function Save(ByVal s As MyClass) As Boolean
Dim cn As SqlClient.SqlConnection = Dal.Connections.MyAppConnection
Dim cmd As New SqlClient.SqlCommand
Try
cmd.Connection = cn
cmd.CommandType = CommandType.StoredProcedure
cmd.CommandText = "proc_save_my_class"
cmd.Parameters.AddWithValue("@param1", s.Foo)
cmd.Parameters.AddWithValue("@param2", s.Bar)
Return True
Finally
Dal.Utility.CleanupAdoObjects(cmd, cn)
End Try
End Function
这是Connection工厂(如果我使用正确的术语):
Friend Shared Function MyAppConnection() As SqlClient.SqlConnection
Dim cn As New SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("MyConnectionString").ToString)
cn.Open()
If cn.State <> ConnectionState.Open Then
' CriticalException is a custom object inheriting from Exception.
Throw New CriticalException("Could not connect to the database.")
Else
Return cn
End If
End Function
这是Dal.Utility.CleaupAdoObjects()函数:
Friend Shared Sub CleanupAdoObjects(ByVal cmd As SqlCommand, ByVal cn As SqlConnection)
If cmd IsNot Nothing Then cmd.Dispose()
If cn IsNot Nothing AndAlso cn.State <> ConnectionState.Closed Then cn.Close()
End Sub
我收到很多“超时到期。在操作完成之前超时的时间,或者服务器没有响应。”用户报告的错误消息。应用程序的DAL打开一个连接,读取或保存数据,然后关闭它。没有连接永远处于打开状态-故意!
在承载SQL Server 2000的Windows 2000 Server上,没有明显的迹象表明存在问题。事件日志中没有任何内容,SQL Server日志中没有任何内容。
超时随机发生-我无法复制。它仅在系统中只有1到5个用户的情况下发生。系统中大约有50位用户也会发生这种情况。对于所有数据库,通过Performance Monitor与SQL Server的连接最多为74个。
超时发生在代码中,该代码既保存到应用程序的不同部分中,又从其中读取。堆栈跟踪不会指向一个或两个有问题的DAL函数。它发生在许多不同的地方。
我的ADO.NET代码似乎可以泄漏连接吗?我已经仔细研究了一下,并且已经读到,如果连接池已满,则可能会发生这种情况。但是,我没有明确设置任何连接池。我什至尝试增加连接字符串中的连接超时,但是超时发生在300秒(5分钟)值之前很久:
<add name="MyConnectionString" connectionString="Data Source=MyServer;Initial Catalog=MyDatabase;Integrated Security=SSPI;Connection Timeout=300;"/>
关于导致这些超时问题的原因,我已经一头雾水。任何想法表示赞赏。
编辑:这是一个WinForms应用程序。
最佳答案
从here:
与Finalize不同,开发人员应显式调用Dispose以释放非托管资源。实际上,您应该在实现该对象的任何对象上显式调用Dispose方法,以释放该对象可能对其持有引用的所有非托管资源。SqlConnection
,SqlCommand
,SqlDataReader
等...全部实现IDisposable
。如果将所有这些实例包含在Using块中,则会自动调用Dispose
,连接将被关闭,并且您不必担心此类问题。启动Reflector,看看自己:(SqlConnection.Dispose
)
protected override void Dispose(bool disposing)
{
if (disposing)
{
this._userConnectionOptions = null;
this._poolGroup = null;
this.Close();
}
this.DisposeMe(disposing);
base.Dispose(disposing);
}
这也使代码更短,因为您不必手动添加Final块来清理ADO.NET对象。
Using connection As SqlConnection("your connection string")
Using command As New SqlCommand("your sql", connection)
connection.Open()
Using dataReader As SqlDataReader = command.ExecuteReader()
'Your stuff here
End Using
End Using
End Using
使用
Using
方法会强制您将ADO.NET对象保持在本地,这对我来说是一件好事。