You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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时延长超时时间,示例:
    // 配置DbContext时指定超时时间,单位为秒,此处设置为60秒
    optionsBuilder.UseSqlServer("你的数据库连接字符串", opt => opt.CommandTimeout(60));
    
    也可以在Context实例中临时修改:pmDbContext.Database.SetCommandTimeout(60);
  • 优化查询索引:代码中涉及的查询过滤字段如果没有索引,会触发全表扫描,不仅查询耗时过长还会加重行锁等待概率。需要给以下字段添加非聚集索引:
    • pm_Requests表:custProfileID、RequestTypeID、StatusId
    • am_RDocuments表:RequestId、ATypeId
    • pm_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 13:06:02