简体   繁体   English

禁用的SQL连接声称已打开C#

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM