我有一个使用SqlConnection
连接到数据库的ASP.NET Web API。我有一个数据访问层类,它有一个包含连接的实例变量。我这样做有几个原因:
SqlTransaction
对象保持在范围内 - 我通过使它也成为实例变量来做到这一点)为了不在DAL调用之间回滚事务。当我对API进行压力测试时,通过每秒提供数百个请求,我遇到了SQL连接池耗尽问题。进一步的调查显示,这似乎是因为没有处理SQL连接。
我理解IDisposable
模式,但我不确定如何在这种情况下使用它。这是我的问题:
using
块或try/catch/finally
块,都需要在单个方法中创建,使用和最终确定对象。在上面可能需要在多个方法调用中持久化的事务示例中,这是不可能的。Dispose()
,而是建议您执行我在问题1中指定的任一选项。IDisposable
只是为了包装另一个管理对象的Dispose
方法,而是你应该只是调用Dispose()当你完成它时对象。"当我在DAL中不确定控制器何时使用SQL连接时,我将如何在这种情况下执行此操作? (另外,这意味着我必须重构控制器,以便在using
区块中将每次调用包装到DAL,所以它只是在路上踢开了。)对我来说,理想的解决方案是能够以某种方式安排在控制器完成处理并返回时在Dispose
对象上调用SqlConnection
方法它对服务器的响应以便传递到前端。要做到这一点"手工"我必须违反上面的第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
等结构中使用一次性物品的需要似乎只限于可以在单个方法中创建和处置对象的情况。
答案 0 :(得分:0)
作为MSDN recommends,你应该使用
using(var cn = new SqlConnection(xx)){ cn.Open(); }
注意:每次都不会打开新连接
如果,SqlConnection从连接池中绘制一个打开的连接 一个是可用的。否则,它建立一个新的连接 SQL Server的实例。
为了控制您的交易 - 您可以使用TransactionScope()
(尽管可能需要MSDTC in some case`s)
否则,如果使用TransactionScope
不是一个选项,并且您希望显式控制您的事务,则唯一的选择是传递连接。因为它是discussed in this POST
你可以用两种方式做“传递”。手动或使用依赖注入( DI )。所有DI容器都允许您控制实例的生命周期。因此,在您的情况下,它可能是“每个请求生存期” 可以在this post
中找到样本答案 1 :(得分:0)
关于这一段。
在一个更通用的平面上,你如何实际处理必须在方法调用之间保持的一次性对象(例如作为实例变量)?在try / catch / finally或者使用的构造中使用一次性物品的需要似乎限制了它们仅用于可以在单个方法中创建和处理对象的情况。
根据经验,负责实例化一次性对象的方法应该是负责处理它的人,可以将它作为参数传递给从实例化方法调用的其他方法,但是,这些方法,不应该负责处理对象。此规则的例外情况可能是,如果您将对象实例化为另一个类,但在这种情况下,此类应该实现IDisposable,并且在使用后应由调用者处理。