[英]Disabled SQL connection claims to be open C#
A number of discussions like this are treating how to check if a SQL connection is open, using the ConnectionState enum. 诸如此类的许多讨论都在处理如何使用ConnectionState枚举检查SQL连接是否打开。 Recently I have experienced that a
ConnectionState.Open
may not always tell the truth in .NET 2.0. 最近,我经历了一个
ConnectionState.Open
可能不会总是说出.NET 2.0的真相。
If the connection is broken from outside while my C# application is running, the connection state is not updated. 如果在我的C#应用程序运行时从外部断开连接,则连接状态不会更新。 Since it still claims that the connection is open, I can not use the following assurance method:
由于它仍然声称连接是打开的,因此我不能使用以下保证方法:
if(Something_Connection.State != ConnectionState.Open)
{
Something_Connection.Close();
Something_Connection.Open();
}
The issue may be reproduced using the following test. 使用以下测试可以重现该问题。 Assuming that you initially have an open connection
m_dbConnection
and a working command line method CommandLineUtils.Run(...)
: 假设您最初具有打开的连接
m_dbConnection
和有效的命令行方法CommandLineUtils.Run(...)
:
[Test]
public void ConnectionStateDoesNotLie()
{
// Close SQL service:
Console.WriteLine(CommandLineUtils.Run("net", "stop \"SQL Server (MSSQLSERVER)\"", 10));
System.Threading.Thread.Sleep(500);
// Check state:
bool stateIsCorrect = m_dbConnection.ConnectionState != ConnectionState.Open;
// Finished testing, restart the SQL service:
Console.WriteLine(CommandLineUtils.Run("net", "start \"SQL Server (MSSQLSERVER)\"", 30));
Assert.IsTrue(stateIsCorrect, "Connection state of closed connetion claims to be open.");
}
My question is if there is a better method to check if a connection has been broken? 我的问题是,是否有更好的方法来检查连接是否断开? Prior to running a query.
在运行查询之前。
Of cause I could run every query in a try-catch
and then try to reopen the connection if an exception is thrown. 当然,我可以在
try-catch
运行每个查询,然后在引发异常时尝试重新打开连接。 But this seems like a clumsy solution. 但这似乎是一个笨拙的解决方案。 I also want to avoid running any dummy update to test the connection prior to every query in my program.
我还想避免在程序中的每个查询之前运行任何虚拟更新来测试连接。
(Why would I want to stop my SQL service during runtime? I would not, but people using my program may sometimes leave it open for 5 hours and then come back expecting it to work. Sometimes their connection may have failed during this period) (我为什么要在运行时停止SQL服务?我不会,但是使用我的程序的人有时可能会使其保持打开状态5个小时,然后回来等待它正常工作。有时他们的连接在此期间可能会失败)
The solution to this problem is to disable connection pooling. 该问题的解决方案是禁用连接池。 For example (I'm using PowerShell here, but it's the same for any other .NET language), using a disabled user named
U
with a password PW
on a server S
: 例如(我在这里使用PowerShell,但是其他任何.NET语言都一样),在服务器
S
上使用名为U
的禁用用户和密码PW
:
$conn = [System.Data.SqlClient.SqlConnection]::new("server=S;user id=U;password=PW")
$conn.Open(); #Throws no exception, reports connection state of Open
$conn = [System.Data.SqlClient.SqlConnection]::new("server=S;user id=DU;password=PW;Pooling=False")
$conn.Open(); #Throws an exception
I'd recommend this pattern: Get the SQL task request, Open the connection, perform the task, Close the connection, respond to the results. 我建议使用这种模式:获取SQL任务请求,打开连接,执行任务,关闭连接,响应结果。
Replace m_dbConnection with m_dbConnectionString. 用m_dbConnectionString替换m_dbConnection。
Your app will be more reliable and any time you need to restart SQL, you won't have a ton of "are you sure -- there are 20 people connected" messages. 您的应用程序将更加可靠,并且每当您需要重新启动SQL时,您都不会收到大量“您确定-有20个人连接”的消息。
Thanks for your comments and answers, I will keep your pattern in mind for future reference, @Dustin_00. 感谢您的评论和回答,我会谨记您的模式,以供将来参考@ Dustin_00。
However in this special case I forgot to specify that the application in view is a database API. 但是,在这种特殊情况下,我忘记指定视图中的应用程序是数据库API。 Therefore the responsibility for opening and closing connections should be forwarded to the programs integrating it, as one sometimes would desire to perform a number of operations on the same connection.
因此,打开和关闭连接的责任应转发给集成它的程序,因为有时希望对同一连接执行许多操作。 But I want to make the API more invulnerable to errors concerning lost connections.
但是,我想使API对与连接丢失有关的错误更加无害。
Since this is the case, and no answers concerning a non-lying connection.State
test could be found, I landed on the solution mentioned as an option in my question. 既然是这种情况,并且没有关于非谎言
connection.State
答案。可以找到状态测试,那么我就提出了我的问题中提到的解决方案。 Where the API performs an extra try, if the query for some reason fails. 如果由于某种原因查询失败,则在API进行额外尝试的地方。 Preferably I would like a trustworthy solution similar to
最好是我想要一个类似于
if (Connection.State != ConnectionState.Open){}.
For others running into the same issue without possibility to avoid it, an example wrapper method is provided here: 对于遇到相同问题而无法避免的其他人,此处提供了示例包装方法:
/// <summary>
/// Wrapper method for OdbcCommand.ExecuteScalar, trying to open connection if the first attempt fails
/// </summary>
/// <param name="readyCommand"></param>
/// <returns>The first column of the first row in the result set, or a null reference if the result set is empty.</returns>
internal static object ExecuteScalar(OdbcCommand readyCommand, bool throwExceptions)
{
if (readyCommand == null)
return -1;
object retVal;
try
{
retVal = readyCommand.ExecuteScalar();
}
catch (Exception e)
{
if (readyCommand.Connection != null)
{
try
{
// Try reopening connection and retry;
readyCommand.Connection.Close();
readyCommand.Connection.Open();
retVal = readyCommand.ExecuteScalar();
}
catch (Exception)
{
if (throwExceptions)
throw e; // rethrow the original exception
retVal = null;
}
}
else
{
if (throwExceptions)
throw e; // rethrow the original exception
retVal = null;
}
}
return retVal;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.