如果存在某些特定的 SqlException(例如连接丢失),我必须修改用于处理 SQL 调用的静态类,以便重试请求。
这是我用来调用存储过程的方法:

public static int CallExecuteNonQuery(string storedProcName, Action<SqlCommand> fillParamsAction, Action afterExecution, BDDSource source)
{
    int result;

    try
    {
        using (var connection = InitSqlConnection(source))

        using (var command = new SqlCommand(storedProcName, connection))
        {
            if (connection.State == ConnectionState.Closed)
                connection.Open();

            command.CommandType = CommandType.StoredProcedure;

            if (fillParamsAction != null)
                fillParamsAction(command);

            result = command.ExecuteNonQuery();

            if (afterExecution != null)
                afterExecution();
        }
    }
    catch (SqlException sqlExn)
    {
        Logger.Exception(string.Format("SQL CRITICAL ERROR. Stored Proc Name : {0}", storedProcName), sqlExn);
        throw;
    }
    catch (Exception exception)
    {
        Logger.Exception(string.Format("SOFTWARE CRITICAL ERROR. Stored Proc Name : {0}", storedProcName), exception);
        throw;
    }
    return result;
}
this link 之后,我尝试根据配置的次数重试请求。
我得到以下代码:
public static int CallExecuteNonQuery(string storedProcName, Action<SqlCommand> fillParamsAction, Action afterExecution, BDDSource source)
{
    bool RetryRequest = true;
    int result = 0;

    for (int i = 0; i < Properties.Settings.Default.Request_MaximumRetry; i++)
    {
        try
        {
            if (RetryRequest)
            {
                using (var connection = InitSqlConnection(source))
                using (var command = new SqlCommand(storedProcName, connection))
                {
                    if (connection.State == ConnectionState.Closed)
                        connection.Open();

                    command.CommandType = CommandType.StoredProcedure;

                    if (fillParamsAction != null)
                        fillParamsAction(command);

                    result = command.ExecuteNonQuery();

                    if (afterExecution != null)
                        afterExecution();
                }

                RetryRequest = false;
            }
        }
        catch (SqlException sqlExn)
        {
            if (sqlExn.Errors.Cast<SqlError>().All(x => (x.Class >= 16 && x.Class < 22) || x.Class == 24))
            {
                RetryRequest = true;
                continue;
            }

            Logger.Exception(string.Format("SQL CRITICAL ERROR. Stored Proc Name : {0}", storedProcName), sqlExn);
            RetryRequest = false;
            throw;
        }
        catch (Exception exception)
        {
            Logger.Exception(string.Format("SOFTWARE CRITICAL ERROR. Stored Proc Name : {0}", storedProcName), exception);
            RetryRequest = false;
            throw;
        }
    }
    return result;
}
但我的修改并不完美。例如,在3次异常重试后,代码不会抛出并在退出循环之前进入continue;部分。

最佳答案

我假设您知道自动重试的注意事项,尤其是当这些涉及非幂等操作时。
与其使用局部变量来跟踪成功或失败,我建议直接为此目的使用控制流关键字:

public static int CallExecuteNonQuery(string storedProcName, Action<SqlCommand> fillParamsAction, Action afterExecution, BDDSource source)
{
    int retryCount = 0;   // recoverable exception will be rethrown
                          // when this count reaches limit

    while (true)   // conditions for breaking out of loop inlined
    {
        try
        {
            using (var connection = InitSqlConnection(source))
            using (var command = new SqlCommand(storedProcName, connection))
            {
                if (connection.State == ConnectionState.Closed)
                    connection.Open();
                command.CommandType = CommandType.StoredProcedure;
                if (fillParamsAction != null)
                    fillParamsAction(command);
                var result = command.ExecuteNonQuery();
                if (afterExecution != null)
                    afterExecution();
                return result;   // on success, return immediately
            }
        }
        catch (SqlException sqlExn)
        {
            // if error is recoverable, and retry count has not exceeded limit,
            // then retry operation
            if (sqlExn.Errors.Cast<SqlError>().All(x => (x.Class >= 16 && x.Class < 22) || x.Class == 24)
                && ++retryCount < Properties.Settings.Default.Request_MaximumRetry)
            {
                continue;
            }

            // otherwise, rethrow exception
            Logger.Exception(string.Format("SQL CRITICAL ERROR. Stored Proc Name : {0}", storedProcName), sqlExn);
            throw;
        }
        catch (Exception exception)
        {
            Logger.Exception(string.Format("SOFTWARE CRITICAL ERROR. Stored Proc Name : {0}", storedProcName), exception);
            throw;
        }
    }
}

关于c# - 在 SqlException 上自动重试请求,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35864154/

10-15 00:53