面对间歇性网络问题,数据库连接可能频繁中断。C#中实现弹性连接的关键是结合重试机制、连接超时控制和异常处理,确保应用在短暂网络波动后能自动恢复,而不是直接崩溃。
使用重试策略应对临时故障
最常见的做法是引入重试逻辑,当数据库操作因网络原因失败时,延迟一段时间后重新尝试。可以手动实现简单重试,也可以借助成熟库如 Polly。
设定最大重试次数(例如3次) 采用指数退避策略,比如等待1秒、2秒、4秒 仅对特定异常重试,如 SqlException、TimeoutException示例:使用 Polly 实现重试:
var retryPolicy = Policy
.Handle<SqlException>(ex => IsTransient(ex))
.Or<TimeoutException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)),
onRetry: (outcome, delay) =>
{
Console.WriteLine($"数据库操作失败,{delay}秒后重试...");
});
// 使用策略执行数据库命令
await retryPolicy.ExecuteAsync(async () =>
{
using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
// 执行查询或命令
});
识别可恢复的异常
不是所有异常都值得重试。需判断 SqlException 的错误号,过滤出典型的临时性问题。
错误号 2: 连接超时 错误号 53, 10054, 10060: 网络相关故障 错误号 121, 233: 连接中断或登录失败(可能临时)判断方法:
private static bool IsTransient(SqlException ex)
{
foreach (SqlError error in ex.Errors)
{
switch (error.Number)
{
case 2: // 超时
case 53: // 找不到服务器/实例
case 10054:
case 10060:
case 121:
case 233:
return true;
}
}
return false;
}
优化连接字符串参数
合理配置连接字符串有助于提升容错能力:
Connect Timeout=30:设置合理的初始连接超时 Command Timeout=60:避免长时间阻塞 Connection Resiliency=true(SQL Server 2014+):启用内置弹性(需配合 EF Core) 考虑启用 MARS(Multiple Active Result Sets)以减少连接争用示例连接字符串:
Server=myserver;Database=mydb;User Id=user;Password=pass; Connect Timeout=30;Command Timeout=60;Connection Resiliency=true;
结合 Entity Framework Core 的内置支持
若使用 EF Core,可直接启用内置的连接弹性:
services.AddDbContext<MyContext>(options =>
options.UseSqlServer(connectionString, sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(10),
errorNumbersToAdd: null);
}));
该机制会自动重试事务性操作,适用于大多数临时故障。
基本上就这些。关键是在合适的地方加入智能重试,避免雪崩式请求,同时准确识别可恢复错误。网络不稳定时,系统依然能保持可用。
