以下是我在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
这是连接工厂(如果我使用正确的术语):
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个用户。对于所有数据库,通过性能监视器与SQL Server的最多连接大约为74。
超时发生在代码中,这些代码既可以保存到应用程序的不同部分,也可以从应用程序的不同部分读取数据库。堆栈跟踪不指向一个或两个违规的DAL功能。它发生在许多不同的地方。
我的ADO.NET代码是否能够泄漏连接?我已经讨论了一下,我已经读过,如果连接池填满,就会发生这种情况。但是,我没有明确设置任何连接池。我甚至试图在连接字符串中增加连接超时,但是在300秒(5分钟)值之前很久就会发生超时:
<add name="MyConnectionString" connectionString="Data Source=MyServer;Initial Catalog=MyDatabase;Integrated Security=SSPI;Connection Timeout=300;"/>
我已经完全失去了导致这些Timeout问题的原因。任何想法都表示赞赏。
编辑:这是一个WinForms应用程序。
答案 0 :(得分:3)
检查连接泄漏的一种方法是将max pool size
添加到连接字符串,例如:
"integrated security=SSPI;server=MyHost;Max Pool Size=1;"
在开发中,我通常使用此设置运行(如果应用程序同时使用两个连接,则为2)。
答案 1 :(得分:2)
来自here:
与Finalize不同,开发人员应明确调用Dispose以释放非托管资源。实际上,您应该在实现它的任何对象上显式调用Dispose方法,以释放对象可能持有引用的任何非托管资源。
SqlConnection
,SqlCommand
,SqlDataReader
等...全部实施IDisposable
。如果将所有这些实例括在一个使用块中,则会自动调用Dispose
,您的连接将被关闭,您不必担心这样的问题。启动反射器并自己查看:(SqlConnection.Dispose
)
protected override void Dispose(bool disposing)
{
if (disposing)
{
this._userConnectionOptions = null;
this._poolGroup = null;
this.Close();
}
this.DisposeMe(disposing);
base.Dispose(disposing);
}
这也使代码更短,因为您不必手动添加Finally块来清理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对象保持在本地,这对我来说是件好事。
答案 2 :(得分:1)
无论状态如何,您都应始终处置Connection:
'If cn IsNot Nothing AndAlso cn.State <> ConnectionState.Closed Then cn.Close()
If cn IsNot Nothing Then cn.Dispose()
我不确定这会导致你的超时,但肯定会有所改善。
答案 3 :(得分:0)
您的存储过程如何在应用程序之外执行?
如果您在Save()中将'return true'移出try / finally块怎么办?
监视perf监视器中的数据库连接,看它们是否会增长。
但我首先要看的是你自己的sprocs - 他们是否按照一致的顺序访问表格,或者你可能会遇到锁定?例如,如果proc1操作table1然后操作table2,而proc2命中table2然后table1,则可能会遇到锁定问题。
答案 4 :(得分:0)
这是一个Windows应用程序还是一个Web应用程序?
使用简单的存储过程或仅使用更复杂的存储过程是否会发生超时?
您是否尝试过运行sql profiler跟踪以查看是否有任何查询确实需要很长时间?
另外,您是否尝试过转换为“使用”语法,以确保对象被关闭并正确处理?