正在尝试避免嵌套的SqlConnection

本文关键字:嵌套 SqlConnection | 更新日期: 2023-09-27 17:57:27

即使嵌套的SqlConnections是否可能,我也不确定,但我真的想远离它。我现在在代码中遇到了范围问题,我正在想办法解决它。

直到最近,我还拥有一个全局SqlConnection,它在应用程序启动时打开,在应用程序完成时关闭。我现在已经发现了.NET连接池的概念,所以我修改了代码,使每个SqlCommand(或它们的组)都使用自己的、新创建和打开的SqlConnection,并信任.NET来管理池和随之而来的开销。

我现在遇到的问题是,我有几个代码块看起来像这样:

using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
{       
    sqlConnection.Open();
    using (SqlCommand sqlCommand1 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand1.ExecuteNonQuery();
    }
    using (SqlCommand sqlCommand2 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand2.ExecuteNonQuery();
    }
    .
    .
    .
    ClassGlobal.WriteAction(action);
}

而ClassGlobal.WriteAction()函数看起来像这样:

public static void WriteAction(MyActionClass action)
{
    using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
    {       
        sqlConnection.Open();
        using (SqlCommand sqlCommand = new SqlCommand("Write the action to the DB", sqlConnection))
        {
            sqlCommand.ExecuteNonQuery();
        }
    }
}

正如您所看到的,在WriteAction()中创建了一个新的SqlConnection,它是从第一个SqlConnection的范围内调用的。不好!我尽量避免这种情况。

在过去,这不会是一个问题,因为没有这些using (SqlConnection)块,并且所有SqlCommands都指向相同的(全局)SqlConnection。很明显,我可以简单地将呼叫移动到WriteAction(),位于using (SqlCommand)的右大括号下方,但是:

  1. 我传递给它的action实例通常是在SqlConnection的范围内实例化和填充的,所以我必须进行更多的更改(大量更改)才能将这些更改移出SqlConnection的范围。它们很多,而且会毛茸茸的
  2. 实际上,我更希望WriteAction()调用可以像上面的例子中那样在SqlConnection范围内,这样我就可以将所有调用封装在TransactionScope中,这在目前是不可能的,但看起来确实是个好主意

以下是我的计划,但我想听听你们中是否有人认为这不是一个好的做法,或者你们是否可以提出一个更好的方法。(我最近发现我的全局SqlConnection不是一个好的做法,这导致我花了很多时间来修复它。我希望将来避免这样的发现)。

我在WriteAction()函数中添加一个参数,使其看起来如下:

public static void WriteAction(MyActionClass action, SqlConnection sqlConnection)
{   
    using (SqlCommand sqlCommand = new SqlCommand("Write the action to the DB", sqlConnection))
    {
        sqlCommand.ExecuteNonQuery();
    }
}

这意味着,我可以简单地将SqlConnection作为参数添加到函数中,而不是将对WriteAction()的调用移动到SqlConnection作用域之外,以便函数中的SQLCommand使用相同的连接,即使该连接已登记到TransactionScope

对于从任何SqlConnection的范围之外调用WriteAction()的少数实例,我可以编写一个重载函数,如下所示:

public static void WriteAction(MyActionClass action)
{
    using (TransactionScope transactionScope = new TransactionScope())
    {
        using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
        {
            sqlConnection.Open();
            WriteAction(action, sqlConnection);
        }
        transactionScope.Complete();
    }
}

这看起来是个好主意吗?还是两年后我会后悔这个决定?

正在尝试避免嵌套的SqlConnection

SqlConnection实例传递给方法是完全可以的。然而,我不确定最后一种方法是不是,没有SqlConnection的重载方法是个好主意。它隐藏了一个事实,即你应该更好地使用另一个,新的过载。它使代码编译,从而防止您修复现在应该修复的代码。

请注意,using块不是问题,而是打开的连接。只要不打开连接,连接池就不需要打开物理连接。

因此,在调用WriteAction:之前关闭连接也是一个可行的选择

using (SqlConnection sqlConnection = new SqlConnection(ClassGlobal.ConnectionString))
{       
    sqlConnection.Open();
    using (SqlCommand sqlCommand1 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand1.ExecuteNonQuery();
    }
    using (SqlCommand sqlCommand2 = new SqlCommand("SQL code here", sqlConnection))
    {
        sqlCommand2.ExecuteNonQuery();
    }
    // ...
    sqlConnection.Close();
    ClassGlobal.WriteAction(action);
    // ... perhaps open it again here
}

来自MSDN:

每当用户在连接上调用Open时,池程序都会查找池中的可用连接。如果池连接可用,它将它返回给调用者,而不是打开一个新的连接。什么时候应用程序在连接上调用Close,池程序返回到活动连接的池集合,而不是关闭它连接返回到池中,可以在上重用下一个CCD_ 34呼叫。

因此,您可以看到,只要不保持外部连接打开,WriteAction中的嵌套using就不是问题。不要将连接实例与物理连接混淆。