【问题标题】:If I use SqlCommand in a method as a parameter, does it block a SqlConnection dispose?如果我在方法中使用 SqlCommand 作为参数,它会阻止 SqlConnection 处置吗?
【发布时间】:2021-08-21 18:48:29
【问题描述】:

我的服务出现连接池问题(已达到最大值),无论我在哪里尝试打开连接,我都会将其包装在 using 语句中以正确处理它,但我认为某些东西不允许它工作.我认为这是因为我使用的方法需要 SqlCommand 作为参数,这是一个示例:

private void QueryDB(string sConnString, SqlCommand oComm)
{
    using (SqlConnection connection = new SqlConnection(sConnString))
    {
        try
        {
            connection.Open();
            oComm.Connection = connection;
            oComm.CommandTimeout = 2;
            oComm.ExecuteNonQuery();
        }
        catch (SqlException e)
        {
            //log exception
        }
        catch (Exception e)
        {
            //log exception
        }
    }
}

之所以这样做是因为我需要在该方法之外组装参数,如下所示:

public void Example1()
{
    using (SqlCommand command = new SqlCommand())
    {
        command.CommandText = "SELECT TOP 1 FROM Table ORDER BY column1 DESC";
        QueryDB(_connString, command));
    }
}

public void Example2()
{
    SqlCommand command= new SqlCommand();
    command.CommandText = "UPDATE Table set column1 = @value where column2 = @number";
    command.Parameters.Add(new SqlParameter { ParameterName = "@value", Value = "someValue", SqlDbType = SqlDbType.VarChar });
    command.Parameters.Add(new SqlParameter { ParameterName = "@number", Value = 3, SqlDbType = SqlDbType.Int });

    QueryDB(_connString, command));
}

Example1 中,我尝试处理SqlCommand,但我不知道它是否可以这样工作。另一件需要考虑的事情是,我每秒运行一个计时器,执行Example1Example2,我不知道这是否与问题有关,有时会发生 Max pool size 错误,而不是每天它会延迟其他查询。我可以做些什么来改善这种行为吗?谢谢

【问题讨论】:

  • 尝试手动处理或尝试SqlCommand.Cancel();EndExecuteNonQuery();
  • 命令执行需要多长时间?如果您每秒都运行它们并且它们花费的时间超过一秒,那么您可能会遇到问题,因为并行运行的数量太多。
  • 与其传入SqlCommand 实例,不如考虑传入一个被调用以填充命令的委托,并在内部构造命令实例。
  • 可能是您的应用程序有死锁堆积。在 SSMS 中连接到实例并使用 Monitor 视图查看活动查询和打开的连接。您应该能够检查状态。他们都在等待还是别的什么?这应该让您对实际发生的事情有更多的了解。
  • 但是您在上面显示的问题中的代码不应保留任何打开的托管连接。 .net CLR 可能会汇集一些非托管连接,但如果您的应用执行正常,这些连接应该是最少的。

标签: c# sql-server sqlconnection sqlcommand


【解决方案1】:

我真的不知道这是否会解决您关于连接池问题的问题,但是,扩展@Jack A 对您的问题的评论,也许,构建代码的更好方法是更改​​您的 @ 987654321@ 方法获取使用必要信息更新 SqlCommand 变量的委托,然后,您可以确保您的 SqlConnectionSqlCommand 在该方法中得到正确处理。

private void QueryDB(string sConnString, Action<SqlCommand> commandDelegate)
{
    using (SqlConnection oCon = new SqlConnection(sConnString))
        using(SqlCommand oComm = new SqlCommand())
        {
            try
            {
                oCon.Open();
                oComm.Connection = oCon;
                oComm.CommandTimeout = 2;
                commandDelegate(oComm);
                oComm.ExecuteNonQuery();
            }
            catch (SqlException e)
            {
                //log exception
            }
            catch (Exception e)
            {
                //log exception
            }
        }
}

然后您可以在代码中通过以下任一方式使用它:

public void Uses()
{
    QueryDB(_connString, (oComm) => oComm.CommandText = "SELECT TOP 1 FROM Table ORDER BY column1 DESC");

    QueryDB(_connString, longerDelegate);
}

private void longerDelegate(SqlCommand oComm)
{
    oComm.CommandText = "UPDATE Table set column1 = @value where column2 = @number";
    oComm.Parameters.Add(new SqlParameter { ParameterName = "@value", Value = "someValue", SqlDbType = SqlDbType.VarChar });
    oComm.Parameters.Add(new SqlParameter { ParameterName = "@number", Value = 3, SqlDbType = SqlDbType.Int });
}

同样,我不确定这是否能解决您的池化问题,但它至少可以确保一切都整齐地包含在您的 QueryDB 方法中。

【讨论】:

    【解决方案2】:

    感谢大家的回复!经过大量研究和修改后,我实施了@Jack A 和@Jhon Busto 的建议。但是你在哪里,约翰它没有解决连接池问题,事实证明真正的问题是计时器,我没有注意到它一直在执行 Example1Example2 但不是每秒都在执行,它是每 50 毫秒或更短,所以我认为它在池中创建了很多连接。我正在更改计时器的 Timer.Interval 属性,但我不知道:

    如果 Enabled 和 AutoReset 都设置为 false,并且计时器之前已启用,则设置 Interval 属性会导致 Elapsed 事件引发一次,就像 Enabled 属性已设置为 true 一样。要设置时间间隔而不引发事件,可以暂时将 Enabled 属性设置为 true,将 Interval 属性设置为所需的时间间隔,然后立即将 Enabled 属性设置回 false。

    来源:https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netframework-4.7.2

    所以,如果我需要更改 Timer.Interval,我会按照 Microsoft 的文档进行操作,我再次测试了所有内容,并且成功了。小心使用定时器!呵呵:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-17
      • 2016-01-12
      • 2011-01-06
      • 2011-04-09
      • 2018-10-27
      • 1970-01-01
      相关资源
      最近更新 更多