EF Core如何实现乐观锁重试 EF Core并发冲突自动重试方法

来源:这里教程网 时间:2026-02-21 17:39:44 作者:

EF Core 实现乐观锁重试,核心是捕获

DbUpdateConcurrencyException
后主动刷新原始值并再次提交。它不是开箱即用的“自动重试”,而是需要你显式编写重试逻辑——但结构清晰、可控性强。

配置并发令牌是前提

没有正确配置并发令牌,EF Core 就不会触发版本校验,自然也不会抛出并发异常。必须确保至少一个属性被标记为并发令牌:

推荐用
1771666242
+
byte[]
类型(如
RowVersion
),SQL Server 自动维护,高效可靠
也可用
[ConcurrencyCheck]
标记任意字段(如
LastUpdated
Version
),但需业务层保证更新时同步赋值
Fluent API 配置更灵活:
modelBuilder.Entity<t>().Property(x => x.RowVersion).IsRowVersion();</t>

手动重试:捕获 → 刷新 → 再保存

这是最常用、最可控的方式。关键在于调用

entry.OriginalValues.SetValues(databaseValues)
,让 EF Core 下次比较时用数据库最新值作为“原始值”:

catch (DbUpdateConcurrencyException ex)
中遍历
ex.Entries
对每个条目调用
entry.GetDatabaseValues()
获取当前库值
entry.OriginalValues.SetValues(...)
覆盖原始快照
最后再调用
context.SaveChanges()
尝试第二次提交

封装成可重试方法(带次数限制)

避免重复写 try-catch,可抽成通用方法。例如:

定义重试次数(如最多 3 次),每次失败后延迟递增(如 100ms、200ms、400ms) 每次重试前重新查询实体(或用
AsNoTracking().FirstOrDefault()
获取最新状态)
若仍失败,可抛出带上下文信息的自定义异常,或返回失败标识供上层处理 注意:不要在同一个 DbContext 实例里无限重试,建议每次重试用新上下文或显式
Reload()

用 Polly 库实现声明式重试策略

如果你项目已引入 Polly,可以简洁地表达重试意图:

Policy.Handle<dbupdateconcurrencyexception>().WaitAndRetry(3, i => TimeSpan.FromMilliseconds(Math.Pow(2, i) * 100))</dbupdateconcurrencyexception>
context.SaveChanges()
包进策略执行块中,失败自动重试
配合
onRetry
回调,在每次重试前刷新实体原始值,保持逻辑完整

基本上就这些。重试本身不复杂,但容易忽略原始值刷新这一步——没它,重试只是反复拿旧快照去比,永远失败。

相关推荐