何时在c#中使用SqlConnection.ClearAllPools()

本文关键字:SqlConnection ClearAllPools 何时 | 更新日期: 2023-09-27 18:30:07

我注意到,在几秒钟内执行200个Insert查询后,我的代码在sqlWrite.ExecuteNonQuery();上出错。我一直认为using会确保资源得到正确的重用,并且不需要做任何事情。这是我第一次遇到这个错误,我已经处理sql/c#将近3年了,做了不同的事情。

using (SqlConnection varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails)) 
{
    using (var sqlWrite = new SqlCommand(preparedCommand, varConnection)) 
    {
        sqlWrite.Parameters.AddWithValue("@var_agr_fname", var_agr_fname == "" ? (object) DBNull.Value : var_agr_fname);
        sqlWrite.ExecuteNonQuery();
    }
}

public static SqlConnection sqlConnectOneTime(string varSqlConnectionDetails)
{
    var sqlConnection = new SqlConnection(varSqlConnectionDetails);
    try
    {
        sqlConnection.Open();
    }
    catch
    {
        DialogResult result = MessageBox.Show(new Form {TopMost = true},
                                              "Błąd połączenia z bazą danych. Czy chcesz spróbować nawiązac połączenie ponownie?",
                                              "Błąd połączenia (000001)",
                                              MessageBoxButtons.YesNo,
                                              MessageBoxIcon.Stop);
        if (result == DialogResult.No)
        {
            if (Application.MessageLoop)
            {
                Application.Exit(); // Use this since we are a WinForms app
            }
            else
            {
                Environment.Exit(1); // Use this since we are a console app
            }
        }
        else
        {
            sqlConnection = sqlConnectOneTime(varSqlConnectionDetails);
        }
    }
    return sqlConnection;
}

错误消息:A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

考虑到这个错误的建议,我应该使用SqlConnection.ClearAllPools();来确保正确重置或丢弃连接。所以我可以使用它,但问题是在哪里使用,什么时候使用?如何知道极限是否会突破?极限在哪里?在50/150/200?还是应该每次循环使用它?

何时在c#中使用SqlConnection.ClearAllPools()

首先,让我说这段代码太可怕了。您将UI与数据连接创建混合在一起。更重要的是,您在catch部分中显示了一个对话框窗口,并执行递归调用!这是非常混乱的,本身就可能导致错误和不可预测的行为。而且(原始)格式使其难以阅读。很抱歉有这么严厉的评论,但你真的应该重新设计这个代码。

除此之外,您的代码应该可以正常工作,但如果出现No process is on the other end of the pipe.错误,则意味着您的数据库和/或SQL Server出现了问题。它看起来像是被堵塞了,只是不接受更多的连接。如果您在短时间内运行一批插入,请尽可能在一个连接上执行。ClearAllPools是一种在发生错误时进行恢复的方法,最好找出它是什么,而不是掩盖它。这就像在牙齿疼痛时服用扑热息痛,却从不去看牙医。

另一件事是,使用多个SqlConnections为每个连接创建单独的事务。这增加了SQL Server的负载,尽管它每秒肯定可以处理数百个以上的事务

此外,您可以将传输更改为命名管道和TCP,以查看它是否更改了任何内容。

"我有一个方法,我可以重复使用它一次或多次。它可以完成从建立连接(或使用已经连接的连接)到将连接返回到池的所有操作。这些都是我得到的建议。这样,如果连接打开,我总是重复使用它,如果它关闭,我总是打开它。"

这听起来像是你重新发明了连接池。如果连接是关闭的,它总是重用连接,如果连接是打开的,它就不能重用连接。

所以关闭catch块中的连接:

public static SqlConnection sqlConnectOneTime(string varSqlConnectionDetails) {
    var sqlConnection = new SqlConnection(varSqlConnectionDetails);
    try {
        sqlConnection.Open();
    } catch {
        //log and
        sqlConnection.Close();
        throw
    }
    return sqlConnection;
}

编辑:老实说,我根本不会使用这样的工厂方法。它们只是不可修复错误的来源。在使用连接的地方创建和打开连接有什么耗时的?

using(SqlConnection varConnection = new SqlConnection(Locale.sqlDataConnectionDetails)) {
    using (var sqlWrite = new SqlCommand(preparedCommand, varConnection)) {
        sqlWrite.Parameters.AddWithValue("@varSecus_agr_fname", varSecus_agr_fname == "" ? (object) DBNull.Value : varSecus_agr_fname);
        varConnection.Open();
        sqlWrite.ExecuteNonQuery();
    }
}

前两个链接来自你的链接问题(不是公认的答案),它们可能也有帮助:

  • http://social.msdn.microsoft.com/Forums/en-US/sqldataaccess/thread/9609559d-f7ce-4bd8-97d0-0003ff7c9c98/
  • http://blogs.msdn.com/b/spike/archive/2009/04/16/a-transport-level-error-has-occurred-when-sending-the-request-to-the-server-provider-tcp-provider-error-0-an-existing-connection-was-forcibly-closed-by-the-remote-host.aspx
  • ExecuteReader需要一个打开且可用的连接。连接';s的当前状态为"正在连接"(不是同一主题,但显然背景相似)

这两个错误:

将请求发送到时发生传输级别错误服务器(提供程序:TCP提供程序,错误:0-现有连接由远程主机强制关闭。)

将请求发送到时发生传输级别错误服务器(提供程序:共享内存提供程序,错误:0-没有进程打开管道的另一端。)

与日期在1900年之前插入SQL的DateTime值有关。这里的Microsoft规则是。。不要在SQL中的DateTime值中存储小于1900年的DateTime。请改用字符串。。。