You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在执行命令时连接中断场景下使用SqlRetryLogicBaseProvider

Azure SQL重试逻辑连接状态处理方案

问题背景

基于.NET Framework 4.8的WinForms应用中,使用SqlRetryLogicBaseProvider为Azure SQL配置重试逻辑。因客户网络不稳定,执行命令时可能出现连接中断,已将错误码11001加入临时错误列表,但测试时遇到以下问题:

  • connection.Open()时网络中断,能正常重试;
  • command.ExecuteReader()时网络中断,首次重试后抛出错误:ExecuteReader requires an open and available Connection. The connection's current state is 'closed',且不再重试连接。

疑问:

  • 应在何处处理连接状态?
  • 是否可在SqlRetryLogicBaseProvider的Retrying事件中处理?
  • 处理后是否会触发重试?

原始代码

var options = new SqlRetryLogicOption()
{
     // 重试5次后抛出异常
     NumberOfTries = 5,
     // 重试前的基础延迟间隔
    DeltaTime = TimeSpan.FromSeconds(5),
     // 重试延迟的最大间隔
     MaxTimeInterval = TimeSpan.FromSeconds(60),
     TransientErrors = new List<int> { -1, -2, 0, 109, -2146232060, 596, 1204, 1205, 1222, 49918, 49919, 49920, 4060, 4221, 40143, 40613, 40501, 40540, 40197, 10929, 10928, 10060, 10054, 10053, 997, 233, 64, 18401, 11001 ,1232}
};

// 创建指数退避重试逻辑提供器
SqlRetryLogicBaseProvider provider = SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options);
provider.Retrying += (object s, SqlRetryingEventArgs e) =>
{
    LogRetry(e);
    // 此处是否可以处理连接丢失?如何处理?
};

try
{    
    using (var connection = new SqlConnection(ConnectionString))
    {   
        // 为连接设置重试提供器
        connection.RetryLogicProvider = provider;                  

        const string selectCmd = "SELECT data FROM mydata WHERE dataID = @dataID";
 
        using (var command = new SqlCommand(selectCmd, connection))
        {                       
            SqlParameter parameter = new SqlParameter("@dataID", SqlDbType.NVarChar, 9);
            parameter.Value = did;
            command.Parameters.Add(parameter);
            // 为命令设置重试提供器
            command.RetryLogicProvider = provider; 
        
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();          
            while (reader.Read())
            {              
                Console.WriteLine("{0}", reader.GetString(0));                
            }
        }
    }
}
catch (Exception ex)
{    
    return String.Empty;
}

编辑1:修改Retrying事件后的问题

修改Retrying事件尝试手动重建连接后,出现内部重试计数器重置为1的问题,导致连接无限重试,无法找到正确更新计数器的方法。

provider.Retrying += (object s, SqlRetryingEventArgs e) =>
{
    LogRetry(e);

    if (s is SqlConnection)
    {
        var conn = s as SqlConnection;
        conn.Close();
        conn.Open();
    }
    else
    {
        if (s is SqlCommand)
        {
            var cmd = s as SqlCommand;
            cmd.Connection.Close();
            cmd.Connection.Open();
        }
    }
};

解决方案

问题根源

当ExecuteReader()因网络中断失败时,SQL连接会被自动关闭,但命令的独立重试逻辑不会自动重建连接,导致重试时连接状态非法。而手动在Retrying事件中打开连接的操作,会触发连接自身的重试逻辑,重置内部重试计数器,进而引发无限重试。

正确处理步骤

  1. 移除命令的重试提供器设置
    无需单独为SqlCommand配置重试提供器,让命令复用SqlConnection的重试逻辑。当命令执行失败触发重试时,连接的重试逻辑会自动处理连接重建,无需手动干预。

    修改后的核心代码:

    try
    {    
        using (var connection = new SqlConnection(ConnectionString))
        {   
            connection.RetryLogicProvider = provider;                  
    
            const string selectCmd = "SELECT data FROM mydata WHERE dataID = @dataID";
     
            using (var command = new SqlCommand(selectCmd, connection))
            {                       
                SqlParameter parameter = new SqlParameter("@dataID", SqlDbType.NVarChar, 9);
                parameter.Value = did;
                command.Parameters.Add(parameter);
                // 移除此行:command.RetryLogicProvider = provider;
         
                connection.Open();
                SqlDataReader reader = command.ExecuteReader();          
                while (reader.Read())
                {              
                    Console.WriteLine("{0}", reader.GetString(0));                
                }
            }
        }
    }
    catch (Exception ex)
    {    
        return String.Empty;
    }
    
  2. 限制Retrying事件的作用范围
    Retrying事件仅用于记录重试日志、发送通知等辅助操作,不要在其中修改连接或命令的状态,避免干扰重试逻辑的内部计数和流程。

  3. 验证临时错误码覆盖
    确认TransientErrors列表包含所有可能的网络类临时错误码,比如10060(连接超时)、10054(连接被重置)等,确保所有符合条件的错误都能触发重试。

无限重试问题的原因

在Retrying事件中手动调用conn.Open()时,该操作会触发连接自身的重试逻辑,导致重试计数器被重新初始化,每次重试都从第1次开始,永远无法达到NumberOfTries设定的上限,最终引发无限重试。

内容的提问来源于stack exchange,提问作者becky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:00:56