EF Core 默认不自动重试数据库连接,需显式调用 EnableRetryOnFailure 启用弹性策略,仅针对网络抖动、瞬时超时等临时错误(如 SQL Server 错误 40613/1205、MySQL 错误 1040/2013)有限重试,不处理主键冲突等永久性错误;重试适用于查询、SaveChangesAsync 和迁移,但不覆盖手动事务;默认指数退避,需关注内存开销、事务幂等性和日志监控;可扩展使用 Polly 实现更精细控制。

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)));
- MySQL(Pomelo)示例(需引用
Pomelo.EntityFrameworkCore.MySql):
services.AddDbContext
options.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 33)),
mySqlOptions => mySqlOptions.EnableRetryOnFailure(5)));
- 重试逻辑自动应用于所有 EF Core 操作:查询、
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 性能、网络链路或数据库负载。










