【问题标题】:If my C# times out with a stored procedure call, does the procedure continue running?如果我的 C# 因存储过程调用而超时,该过程是否会继续运行?
【发布时间】:2016-04-21 14:42:34
【问题描述】:

我只有一个一般类型的问题。如果我有一个调用 SQL Server 存储过程的 C# 应用程序,并且 C# 应用程序超时,服务器上的过程调用是否会继续运行直到完成?

【问题讨论】:

  • 有两种不同的超时...有一个连接超时和一个命令超时
  • 真的不清楚 C# 应用程序“超时”是什么意思。存储过程不会在 C# 应用程序上等待任何东西。一旦 SP 启动,它将运行到完成。但是,如果在执行 SP 后某些 C# 代码导致应用程序冻结并最终终止,并且这发生在显式事务范围内,那么是的,它会回滚。
  • 这是一个正在发生的 CommandTimeout。有问题的过程不返回任何数据,理论上不需要 C# 应用程序来启动过程调用。没有事务,只是调用程序。所以你是说如果 CommandTimeout “超时”,程序会继续运行吗?

标签: c# sql-server stored-procedures command-timeout


【解决方案1】:

没有。下面是复制品。当超时发生时,正在运行的进程将被杀死,立即停止它。如果您没有指定事务,则在超时之前已在存储过程中完成的工作将被保留。同样,如果与服务器的连接被某种外力切断,SQL Server 将杀死正在运行的进程。

using (var conn = new SqlConnection(@"Data Source=.;Initial Catalog=Test;Integrated Security=True"))
{
    conn.Open();

    using (var setupTable = new SqlCommand(@"
        IF NOT EXISTS (
            SELECT *
            FROM
                sys.schemas s
                    INNER JOIN sys.tables t ON
                        t.[schema_id] = s.[schema_id]
            WHERE
                s.name = 'dbo' AND
                T.name = 'TimeoutTest')
        BEGIN
            CREATE TABLE dbo.TimeoutTest
            (
                ID int IDENTITY(1,1) PRIMARY KEY,
                CreateDate datetime DEFAULT(getdate())
            );
        END

        -- remove any rows from previous runs
        TRUNCATE TABLE dbo.TimeoutTest;", conn))
    {
        setupTable.ExecuteNonQuery();
    }

    using (var checkProcExists = new SqlCommand(@"
        SELECT COUNT(*)
        FROM
            sys.schemas s
                INNER JOIN sys.procedures p ON
                    p.[schema_id] = s.[schema_id]
        WHERE
            s.name = 'dbo' AND
            p.name = 'AddTimeoutTestRows';", conn))
    {
        bool procExists = ((int)checkProcExists.ExecuteScalar()) == 1;

        if (!procExists)
        {
            using (var setupProc = new SqlCommand(@"
                CREATE PROC dbo.AddTimeoutTestRows
                AS
                BEGIN

                    DECLARE @stop_time datetime;

                    SET @stop_time = DATEADD(minute, 1, getdate());

                    WHILE getdate() < @stop_time
                    BEGIN
                        INSERT INTO dbo.TimeoutTest DEFAULT VALUES;

                        -- wait 10 seconds between inserts
                        WAITFOR DELAY '0:00:10';
                    END

                END", conn))
            {
                setupProc.ExecuteNonQuery();
            }
        }
    }

    bool commandTimedOut = false;

    try
    {
        using (var longExecution = new SqlCommand("EXEC dbo.AddTimeoutTestRows;", conn))
        {
            // The time in seconds to wait for the command to execute.
            // Explicitly setting the timeout to 30 seconds for clarity.
            longExecution.CommandTimeout = 30;

            longExecution.ExecuteNonQuery();
        }
    }
    catch (SqlException ex)
    {
        if (ex.Message.Contains("Timeout"))
        {
            commandTimedOut = true;
        }
        else
        {
            throw;
        }
    }

    Console.WriteLine(commandTimedOut.ToString());

    // Wait for an extra 30 seconds to let any execution on the server add more rows.
    Thread.Sleep(30000);

    using (var checkTableCount = new SqlCommand(@"
        SELECT COUNT(*)
        FROM
            dbo.TimeoutTest t;", conn))
    {
        // Only expecting 3, but should be 6 if server continued on without us.
        int rowCount = (int)checkTableCount.ExecuteScalar();

        Console.WriteLine(rowCount.ToString("#,##0"));
    }
}

Console.ReadLine();

产生以下输出

True
3

即使从 Management Studio 运行存储过程会在一分钟的时间范围内添加 6 行。

【讨论】:

    【解决方案2】:

    简短的回答是肯定的......这里有一些信息来支持我的主张

    实际上有几个地方应用程序可以“超时”,但一个是命令执行超时......

    命令执行超时 - 此属性是命令执行或结果处理期间所有网络读取的累积超时。返回第一行后仍有可能超时,不包括用户处理时间,只包括网络读取时间。

    如果超时,命令不会自行回滚。如果超时,这将需要围绕代码进行事务。

    如果在返回行时可能发生超时,则意味着在 C# 不会告诉 SQL Server 停止运行命令的任何时候都可能发生超时。可以做一些事情,例如将命令包装在事务中

    来源:https://blogs.msdn.microsoft.com/mattn/2008/08/29/sqlclient-timeouts-revealed/...和经验

    【讨论】:

    • 您链接到的大部分描述是检索行。在我的情况下,存储过程不返回任何结果。它开始了每晚的导入工作。因此,如果 C# CommandTimeout 在该过程在服务器上运行时超时,即使与它的 C# 连接超时,它是否会继续在服务器上运行?
    • 我认为描述 ... 仍然可以在第一行之后发生,这意味着它也可以在第一行返回之前的任何时间发生。所有超时意味着这花费的时间比它应该花费的时间多
    【解决方案3】:

    如果您使用的是 SQlCommand 类,一旦应用程序超时,查询执行将被回滚。

    【讨论】:

    • 不确定我是否同意这取决于查询是否包含在事务中
    【解决方案4】:

    我对此的想法是,这完全与调用过程打开的连接有关。 如果您的代码在 using 块中执行,或者如果它被垃圾收集,那么我认为 SP 的执行将被回滚。

    【讨论】:

      【解决方案5】:
                  Conn = new SqlConnection(ConnStr);
                  Conn.Open();
                  myCommand = new SqlCommand();
                  myCommand.CommandTimeout = 180000;
                  myCommand.Connection = Conn;
                  myCommand.CommandType = System.Data.CommandType.StoredProcedure;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-05
        • 2011-03-02
        • 1970-01-01
        • 2016-08-02
        • 2020-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多