使用带有connection.open的语句

时间:2012-02-16 18:31:32

标签: c# ado.net

我正在查看一些代码并与同事讨论。

特别是一段看起来像这样的代码。

    [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
        }
    }

4 个答案:

答案 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方法中打开连接。

当然,此处发布的所有其他论点仍然有效;如果您要立即使用它,则应该只打开连接。