在 Entity Framework Core 中,`CreateExecutionStrategy()` 用于创建 **执行策略(Execution Strategy)**,其核心目的是处理数据库操作的 **暂时性故障(Transient Failures)**,例如网络波动、数据库连接中断、死锁等瞬时错误。这一机制尤其在云环境(如 Azure SQL)或高并发场景中至关重要,能显著提升应用程序的 **容错能力** 和 **健壮性**。
---
### **1. 执行策略的作用**
执行策略通过以下方式工作:
- **自动重试**:当检测到 **可重试的异常**(如 `SqlException` 且错误码标识为暂时性错误)时,自动重新执行操作。
- **事务一致性**:在重试过程中确保事务的完整性和一致性,避免数据部分提交。
- **灵活配置**:支持自定义重试次数、重试间隔和异常过滤条件。
例如,SQL Server 的默认执行策略(`SqlServerRetryingExecutionStrategy`)会针对常见的暂时性错误(如错误号 `40613`、`40197`)自动重试操作。
---
### **2. 为什么在事务代码中需要执行策略?**
在事务操作中,数据库连接可能因瞬时故障中断,导致事务失败。如果直接使用简单的事务代码(如 `BeginTransaction` 和 `Commit`),这些错误可能导致整个操作不可恢复。执行策略通过以下方式优化事务处理:
#### **场景示例**
假设以下代码没有执行策略:
```csharp
using var transaction = await _dbContext.BeginTransactionAsync();
try
{
// 操作1:更新订单状态
await _dbContext.SaveChangesAsync();
// 操作2:扣减库存
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception ex)
{
await transaction.RollbackAsync();
throw;
}
```
- **问题**:如果 `操作2` 执行时发生暂时性错误(如网络抖动),整个事务会回滚,但不会自动重试。用户需要手动重新提交请求。
- **解决**:通过执行策略包裹事务代码,自动重试整个事务逻辑。
---
### **3. 执行策略与事务的协作**
在您提供的代码中:
```csharp
var strategy = _dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
using (var transaction = await _dbContext.BeginTransaction())
{
await next(); // 执行业务操作(可能包含多次 SaveChanges)
await _dbContext.CommitTransaction(transaction);
}
});
```
- **关键点**:
1. **事务包裹在策略中**:执行策略会确保整个事务块(`BeginTransaction` → 业务操作 → `Commit`)在遇到可重试错误时自动重试。
2. **重试的原子性**:每次重试会重新创建事务,确保每次尝试是独立的,避免残留状态。
3. **幂等性要求**:业务操作需设计为幂等(即重试不会导致重复副作用),例如通过唯一约束或幂等令牌。
---
### **4. 执行策略的典型配置**
在 EF Core 中,执行策略通常通过 `DbContextOptionsBuilder` 配置:
```csharp
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(
connectionString,
options => options.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null
)
)
);
```
- `EnableRetryOnFailure`:启用 SQL Server 的默认重试策略。
- `maxRetryCount`:最大重试次数。
- `maxRetryDelay`:重试之间的最大延迟。
---
### **5. 代码中为何需要显式调用 `CreateExecutionStrategy()`?**
默认情况下,执行策略已通过 `EnableRetryOnFailure` 启用,但在以下场景需手动调用 `CreateExecutionStrategy()`:
- **需要自定义事务边界**:当业务逻辑需要显式控制事务范围时(如跨多个 `SaveChanges` 或混合 EF 与非 EF 操作)。
- **手动触发重试逻辑**:例如在 MediatR 的管道行为(Pipeline Behavior)中统一封装事务和重试逻辑(如您提供的代码)。
---
### **6. 执行策略的注意事项**
- **事务作用域**:执行策略必须包裹整个事务(包括 `BeginTransaction` 和 `Commit`),否则重试时可能因事务未重置而失败。
- **避免副作用**:确保事务内的操作是幂等的,避免重试导致重复执行(如发送邮件、调用外部 API)。
- **上下文状态**:重试时,`DbContext` 的跟踪实体状态会被重置,需确保每次重试操作是完整的(例如重新加载数据)。
---
### **总结**
在您的代码中,`CreateExecutionStrategy()` 的作用是:
1. **容错保障**:自动重试因暂时性故障失败的事务操作。
2. **事务完整性**:确保事务块在重试时保持原子性。
3. **统一管理**:在 MediatR 管道中集中处理事务和重试逻辑,提升代码可维护性。
如果未使用执行策略,瞬时错误可能导致事务直接失败,需要客户端手动重试,降低系统可靠性。