我正在查看一些代码并与同事讨论。
特别是一段看起来像这样的代码。
[Test]
public void TestNormalWay()
{
using(var cn = GetConnection())
{
cn.Open();
// do stuff
}
}
问题出现了:
“为什么不将cn.Open移动到GetConnection方法中。”
我说如果“打开”抛出异常处理就不会被调用。他的回答是
“那是什么。没有打开连接,所以为什么需要这样做 关闭(或处置)?“
对我来说,这只是一个不想知道我是否需要处理/关闭的问题所以我会重复cn.Open代码而不是将其移动到共享函数中。
但这很有趣......所以我在SQL Server Connection Pooling (ADO.NET)做了一些阅读
对我而言,目前尚不清楚是否存在调用cn.Open并抛出异常需要调用dispose的场景。
因此,在下面的示例中,“TestNormalWay”与“WhyNotDoItThisWay”之间存在任何差异
protected static DbConnection GetConnection()
{
DbConnection cn = new SqlConnection("SomeConnecitonstring... ");
return cn;
}
protected static DbConnection GetConnectionDangerousVersion()
{
DbConnection cn = new SqlConnection("SomeConnecitonstring... ");
cn.Open(); // this will throw.. .dispose not called
return cn;
}
[Test]
public void TestNormalWay()
{
using(var cn = GetConnection())
{
cn.Open();
// do stuff
}
}
[Test]
public void WhyNotDoItThisWay()
{
using(var cn = GetConnectionDangerousVersion())
{
// do stuff
}
}
答案 0 :(得分:7)
您编写代码的方式总是想要在创建连接后立即打开连接,因此没有区别。
但是,您可以多次打开和关闭连接,并且在设计的代码中有很大的不同。
我可能想编写一些代码,其中我有一个长时间运行的例程,它接受一个连接对象并随着时间的推移打开并关闭它。例程可能不关心连接对象是如何创建的。因此,将创建连接的行为与打开和关闭它的行为分开是有利的。
关于资源管理问题,我同意这不是问题。创建SQL连接对象本身并不会锁定任何资源,而是打开它获取池化连接的行为。如果open返回异常,我认为假设没有打开连接是合理的。
答案 1 :(得分:6)
我倾向于只返回SqlConnection
的实例而不在您的方法中调用Open()
。如果需要,应该这样做。您的实用程序功能不需要它。
其中一个原因是,有些对象需要SqlConnection
,但不一定需要打开它们。例如,SqlDataAdapter
需要SqlConnection
,并在其自身内处理它的打开和关闭。当然,你可以在传递之前打开一个连接,但是你必须明确关闭它。
回过头几步,调用代码应该负责处理与SqlConnection
完全相关的内容。
答案 2 :(得分:1)
您可以在第二个“危险”版本中围绕.Open()调用放置一个try / catch,这样如果它在打开时抛出异常,您仍在处理连接。
答案 3 :(得分:0)
在SqlConnection的内部达到顶峰后,我非常相信它并不重要。快速测试似乎证实了这一点:
static void Main( string[] args )
{
Func<SqlConnection> getConnection =
() =>
{
var connection =
new SqlConnection(
"Initial Catalog=myDatabase;Server=(local);Username=bogus;password=blah;Connect Timeout=10;" );
connection.Open();
return connection;
};
while(true)
{
try
{
using( var connection = getConnection() )
{
var cmd = new SqlCommand( "SELECT 1", connection ) {CommandType = CommandType.Text};
cmd.ExecuteNonQuery();
}
}
catch ( Exception )
{
// ignore exception
}
}
}
我将此代码运行了几分钟,并附带了一个分析器。它不仅运行速度很快,而且还没有泄漏任何内存。这几乎让我相信可以在GetConnection方法中打开连接。
当然,此处发布的所有其他论点仍然有效;如果您要立即使用它,则应该只打开连接。