EF Core中SaveChanges()方法偶发超时错误的解决方案咨询
public class PMDbContext : DbContext{ public PMDbContext(); public DbSet<pm_Requests> pm_Requests { get; set; } public DbSet<am_RDocuments> am_RDocuments { get; set; } public DbSet<pm_RDocAtt> pm_RDocAtt { get; set; } // 其余未使用的DbSet省略 } using (var pmDbContext = new PMContext()) { var custProfile = GetProfileDetails(prevResponse, pmDbContext); var request = GetRequestDetails(prevResponse, pmDbContext); if (custProfile != null) { custProfile.AccessId = prevResponse.AccessId.ToString(CultureInfo.InvariantCulture); custProfile.LastModifiedDate = DateTime.Now; if (ServiceVo.PmAgreementDate != ServiceVo.PEffectiveDateEffectiveDate) { custProfile.EffectiveDate = ServiceVo.AgreementDate; if (custProfile.EffectiveDate.HasValue) { var initRId = pmDbContext.pm_Requests.Where(i => i.custProfileID == custProfile.custProfileId && i.RequestTypeID == 1 && i.StatusId == (int)RunningServiceStatus.Completed).Select(p => p.RequestId).FirstOrDefault(); if (initRId != 0) { var rDocumentId = pmDbContext.am_RDocuments.Where(p => p.RequestId == initRId && p.ATypeId == custProfile.MainATypeId).Select(p => p.RDocId).FirstOrDefault(); if (rDocumentId != 0) { var rDocAtt = pmDbContext.pm_RDocAtt.FirstOrDefault(p => p.RId == rDocumentId); if (rDocAtt != null) { rDocAtt.EffFrom = ServiceVo.AgreementDate; } } } } } } pmDbContext.SaveChanges(); }
SaveChanges偶发超时解决方案
- 调整命令超时时间:默认EF的命令超时为30秒,遇到数据库高峰、大表查询场景时容易触发超时,可以在配置DbContext时延长超时时间,示例:
也可以在Context实例中临时修改:// 配置DbContext时指定超时时间,单位为秒,此处设置为60秒 optionsBuilder.UseSqlServer("你的数据库连接字符串", opt => opt.CommandTimeout(60));pmDbContext.Database.SetCommandTimeout(60); - 优化查询索引:代码中涉及的查询过滤字段如果没有索引,会触发全表扫描,不仅查询耗时过长还会加重行锁等待概率。需要给以下字段添加非聚集索引:
pm_Requests表:custProfileID、RequestTypeID、StatusIdam_RDocuments表:RequestId、ATypeIdpm_RDocAtt表:RId
- 减少EF跟踪开销:如果
GetProfileDetails、GetRequestDetails中存在大量不需要修改的实体查询,使用AsNoTracking()查询,避免ChangeTracker堆积过多无需更新的实体,降低SaveChanges时的遍历校验开销。如果确定只需要更新少量字段,可以手动Attach实体并仅标记修改字段,示例:pmDbContext.Attach(custProfile); pmDbContext.Entry(custProfile).Property(x => x.LastModifiedDate).IsModified = true; pmDbContext.Entry(custProfile).Property(x => x.EffectiveDate).IsModified = true; - 优化事务隔离级别:默认的读提交隔离级别下,读写操作会互相阻塞,可以开启数据库的已提交读快照隔离(RCSI),避免读取阻塞写入,降低死锁概率。
- 添加瞬时故障重试机制:偶发超时大概率是网络波动、数据库瞬时压力过高导致的,可以引入重试策略,对
SaveChanges操作添加3-5次重试,每次间隔1-2秒,应对瞬时故障。 - 使用异步保存方法:将
SaveChanges()替换为await SaveChangesAsync(),避免同步调用阻塞线程,提升高并发场景下的吞吐量。
内容的提问来源于stack exchange,提问作者the_coder_guy
相关产品推荐
相关产品推荐

