正在尝试避免嵌套的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)
的右大括号下方,但是:
- 我传递给它的
action
实例通常是在SqlConnection
的范围内实例化和填充的,所以我必须进行更多的更改(大量更改)才能将这些更改移出SqlConnection
的范围。它们很多,而且会毛茸茸的 - 实际上,我更希望
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
的重载方法是个好主意。它隐藏了一个事实,即你应该更好地使用另一个,新的过载。它使代码编译,从而防止您修复现在应该修复的代码。
请注意,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
就不是问题。不要将连接实例与物理连接混淆。