EF Core 本身不自动重试失败的数据库连接,但可以通过 EnableRetryOnFailure 显式启用弹性连接策略,专门应对网络抖动、瞬时超时、连接池耗尽等短暂故障。它不是万能兜底,而是针对可识别的“临时性错误”(如 SQL Server 错误 40613、40197、1205 等)做有限重试。
启用内置重试策略(最常用)
在注册 DbContext 时配置即可,适用于 SQL Server 和 MySQL(Pomelo 提供支持):
SQL Server 示例(.NET 6+ Program.cs 或 Startup.cs):services.AddDbContext
options.UseSqlServer(connectionString, sqlOptions =>
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null)));
Pomelo.EntityFrameworkCore.MySql):
services.AddDbContext
options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 33)),
mySqlOptions => mySqlOptions.EnableRetryOnFailure(5)));
SaveChangesAsync()、迁移执行(如
Database.Migrate()) 默认使用指数退避算法控制间隔,避免雪崩式重试 注意:事务内手动开启的
BeginTransactionAsync()不会被自动包裹进重试范围,整个事务需由你自行保障原子性
识别哪些错误会被重试
EF Core 内置判断逻辑,对以下典型场景自动视为可重试:
SQL Server:连接超时(1205)、服务繁忙(40613)、连接中断(10928)、临时网络丢包等 MySQL:连接拒绝(1040)、连接超时(2013)、Too many connections(1040)等(依赖 Pomelo 实现) 不会重试:主键冲突、外键约束失败、语法错误、权限不足等业务或永久性错误 可通过errorNumbersToAdd补充自定义错误码(如 Azure SQL 的特定限流码)
重试带来的影响与注意事项
启用后不是“零成本”,需关注实际运行表现:
内存开销增加:EF Core 会缓冲查询结果集,大查询 + 重试可能显著提升内存占用 事务边界变敏感:每个SaveChangesAsync()成为独立可重试单元;跨多个 SaveChanges 的业务逻辑需自行幂等设计 日志很重要:建议启用 EF Core 日志(如
LogLevel.Information级别),观察重试是否频繁触发——高频重试往往说明存在根本问题(如连接池设置过小、慢查询拖垮服务) 连接字符串中的
ConnectRetryCount和
ConnectRetryInterval是 ADO.NET 层参数,与 EF Core 的
EnableRetryOnFailure并存但作用域不同,一般推荐只用后者,更可控
需要更强控制?用 Polly 手动封装
当内置策略不够灵活(比如只想重试某几个关键查询、要记录每次重试上下文、或整合熔断/降级),可用 Polly 库手动实现:
安装:Polly+
Polly.Extensions.Http(虽名含 Http,也适用于 DB 场景) 按异常类型判断是否临时故障(例如封装
IsTransient方法) 支持自定义退避策略(线性、指数、Jitter)、重试前/后钩子、熔断器联动 适合关键路径(如支付确认、订单创建),不建议全局无差别套用
基本上就这些。合理设好重试次数和延迟,配合日志观察,能明显改善云环境或高并发下的数据库稳定性。但它不是掩盖架构问题的胶带——如果重试频繁发生,优先查连接池、SQL 性能、网络链路或数据库负载。
