我有一个ASP.NET Web API,它使用SqlConnection
连接到数据库。我有一个数据访问层类,它有一个包含连接的实例变量。我这样做了几个方面的原因:在ASP.NET中正确配置SqlConnection?
- 调用代码可以覆盖在DAL类(例如,用于测试代码)
- 也有一些情况下API控制器需要打开的构造函数的连接字符串一个SQL连接,开始一个事务,然后在提交(或回滚)事务之前调用DAL类中的几个方法。因此,关闭并重新打开每个方法的连接将不起作用,因为我必须保持连接处于打开状态(甚至保留
SqlTransaction
对象的范围 - 我会通过将它作为一个实例变量来实现),以便不必该事务在DAL调用之间回滚。 - 它还简化了代码的可读性,所以你不会复制遍布各处的代码来打开SQL连接。
当我对API进行压力测试时,通过每秒提供数百次请求,我碰到了SQL连接池耗尽问题。进一步调查显示,这似乎是因为SQL连接没有被处置。
我明白IDisposable
模式,但我不确定在这种情况下如何使用它。这里是我的问题:
- 使用
using
块,或try/catch/finally
块,都需要被创建,使用和单一方法中完成的对象。在可能需要跨多个方法调用持续存在的事务上面的示例中,这是不可能的。 - 微软(和SO其他职位)建议针对干脆把呼叫
Dispose()
在对象的析构,而不是建议你做任何的我在问题中指定的选项1. - 微软还表示,你不应该实施
IDisposable
你自己只是为了包装另一个管理对象的方法Dispose
,但是你应该“在完成对象时简单地调用对象的Dispose()。”在控制器完成使用SQL连接后,如果我不确定从DAL内部执行此操作,我该怎么做? (另外,这意味着我必须重构控制器来包装每次调用DAL在using
块,所以它只是拖延时间的道路。)
对我来说,理想解决方案将是当控制器完成处理并且将其对服务器的响应返回以传送到前端时,能够以某种方式安排在SqlConnection
对象上调用Dispose
方法。要做到这一点“手工”,我将不得不违反上面的第3点,并在我的DAL上创建我自己的Dispose
方法,然后简单地调用SqlConnection的Dispose
。此外,这意味着我必须重构所有控制器中的许多方法以包装using
块中的所有DAL访问权限。看起来ASP.NET在控制器返回时不会自动调用Dispose
,这就是连接泄漏的原因。
在任何一种情况下,它也会产生更详细的代码。例如:
// we only need one method call from the DAL, so let's be compact
string someData = new DAL().GetSomeData(someParam);
现在已经写出为:
// we have to initialize here to keep the variable from falling out of scope after the using blocks
// we also must provide some value because the using block implies try/catch.
string someData = "";
using (DAL d = new DAL()) {
someData = d.getSomeData(someParam);
}
什么是实现这个建议的方法是什么?
在一个更通用的平面上,您如何处理一个必须在方法调用之间持续存在的可丢弃对象(例如作为实例变量)?在像try/catch/finally
或using
这样的结构中使用一次性物品的需要似乎限制了它们的使用,仅限于可以在单一方法中创建和处理物体的情况。
如果您使用DI容器 - 您可以让它在请求结束时处理您的资源。虽然我个人更喜欢自己管理关系 - 当我需要时打开,做些东西,关闭。 – Evk