我是否泄漏了 ADO.NET 连接?
这是我在 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;"/>
我已经完全不知道是什么导致了这些超时问题。任何想法表示赞赏。
编辑:这是一个 WinForms 应用程序。
Here is an example of my code in a DAL. All calls to the database's Stored Procedures are structured this way, and there is no in-line 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
Here is the Connection factory (if I am using the correct term):
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
Here is the Dal.Utility.CleaupAdoObjects() function:
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
I am getting a lot of "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding." error messages reported by the users. The application's DAL opens a connection, reads or saves data, and closes it. No connections are ever left open - intentionally!
There is nothing obvious on the Windows 2000 Server hosting the SQL Server 2000 that would indicate a problem. Nothing in the Event Logs and nothing in the SQL Server logs.
The timeouts happen randomly - I cannot reproduce. It happens early in the day with only 1 to 5 users in the system. It also happens with around 50 users in the system. The most connections to SQL Server via Performance Monitor, for all databases, has been about 74.
The timeouts happen in code that both saves to, and reads from, the database in different parts of the application. The stack trace does not point to one or two offending DAL functions. It's happened in many different places.
Does my ADO.NET code appear to be able to leak connections? I've goolged around a bit, and I've read that if the connection pool fills up, this can happen. However, I'm not explicitly setting any connection pooling. I've even tried to increase the Connection Timeout in the connection string, but timeouts happen long before the 300 second (5 minute) value:
<add name="MyConnectionString" connectionString="Data Source=MyServer;Initial Catalog=MyDatabase;Integrated Security=SSPI;Connection Timeout=300;"/>
I'm at a total loss already as to what is causing these Timeout issues. Any ideas are appreciated.
EDIT: This is a WinForms application.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
检查连接泄漏的一种方法是将最大池大小添加到连接字符串,例如:
在开发中,我通常使用此设置运行(如果应用程序同时使用两个连接,则使用大小 2。)
One way to check for connection leaks is to add
max pool size
to the connection string, like:In development I usually run with this setting (or size 2 if the application uses two connections simultaneously.)
来自此处:
SqlConnection
、SqlCommand
、SqlDataReader
等...都实现了IDisposable
。如果您将所有这些实例包含在一个Using块中,那么将自动调用Dispose
,您的连接将被关闭,并且您不必担心此类问题。启动 Reflector 并亲自查看一下:(SqlConnection.Dispose
)这也使代码更短,因为您不必手动添加 Final 块来清理 ADO.NET 对象。
使用
Using
方法强制您将 ADO.NET 对象保留在本地,这对我来说是一件好事。From here:
SqlConnection
,SqlCommand
,SqlDataReader
, etc... all implementIDisposable
. If you enclose all these instances in a Using block, thenDispose
will be called automatically, your connections will be closed, and you won't have to worry about issues like this. Fire up Reflector and take a look for yourself: (SqlConnection.Dispose
)This also makes the code shorter in that you don't have to manually add a Finally block to clean up your ADO.NET objects.
Using the
Using
approach forces you to keep your ADO.NET objects local, which to me is a good thing.您应该始终释放连接,无论其状态如何:
我不确定这是否会导致超时,但这肯定是一种改进。
You should always Dispose the Connection, regardless of its State:
I'm not sure it this could cause your timeouts but it certainly is an improvement.
您的存储过程在应用程序之外如何执行?
如果将“return true”移出 Save() 中的 try/finally 块会怎样?
在性能监视器中监视数据库连接以查看它们是否增长。
但我首先要查看的是您的存储过程本身 - 它们是否以一致的顺序访问表,或者您是否可能遇到锁?例如,如果 proc1 操作 table1,然后操作 table2,而 proc2 操作 table2,然后操作 table1,则可能会遇到锁定问题。
How do your stored procedures perform outside of your application?
What if you moved the 'return true' out of your try/finally block in Save()?
Monitor DB connections in perf monitor to see if they grow.
But the first place I would look is your sprocs themselves - do they access tables in consistent order or might you be running into locks? For example, if proc1 manipulates table1 and then table2, while proc2 hits table2 and then table1 you might run into locking issues.
这是 Windows 应用程序还是 Web 应用程序?
超时是发生在简单的存储过程中还是仅发生在更复杂的存储过程中?
您是否尝试过运行 sql profiler 跟踪来查看是否有任何查询确实花费了很长时间?
另外,您是否尝试过转换为“using”语法,以确保对象被正确关闭和处置?
Is this a windows app or a web app?
Do the timeouts happen with simple stored procedures or just with more complicated ones?
Have you tried running a sql profiler trace to see if any queries really are taking a long time?
Also, have you tried converting to the "using" syntax, which ensures that the objects get closed and disposed of properly?