0

0

c# 在高并发下使用 EF Core 的 SaveChangesAsync 和并发冲突

煙雲

煙雲

发布时间:2026-01-22 12:09:11

|

786人浏览过

|

来源于php中文网

原创

EF Core 的 SaveChangesAsync 默认不处理并发冲突,需用 IsConcurrencyToken 标记字段启用乐观并发检查;捕获 DbUpdateConcurrencyException 后须手动合并业务逻辑并重试,避免简单覆盖,并考虑限流、退避及读写分离等高并发优化策略。

c# 在高并发下使用 ef core 的 savechangesasync 和并发冲突

EF Core 的 SaveChangesAsync 默认不处理并发冲突

调用 SaveChangesAsync 时,EF Core 只是把待提交的变更翻译成 SQL 执行,不会主动检测或重试并发写入。如果两个请求同时读取同一行、各自修改后都调用 SaveChangesAsync,后提交者会直接覆盖前者的修改——除非你显式启用并发控制。

用 IsConcurrencyToken 标记字段才能触发乐观并发检查

EF Core 的并发冲突检测依赖数据库层面的“版本戳”(如 rowversiontimestamp 字段),不是靠应用层锁或时间戳比对。必须在实体中声明一个属性并标记为并发令牌:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    [Timestamp] // SQL Server 专用,生成 rowversion 列
    public byte[] RowVersion { get; set; }
}

或者用 Fluent API(更通用):

modelBuilder.Entity()
    .Property(p => p.RowVersion)
    .IsConcurrencyToken();
  • 没有这个标记,SaveChangesAsync 即使遇到数据库行已被修改,也不会抛出 DbUpdateConcurrencyException
  • [Timestamp] 仅适用于 SQL Server;PostgreSQL/MySQL 需用 intdatetime 类型 + IsConcurrencyToken() 配合手动更新逻辑
  • 字段值必须由数据库自动生成(如 rowversionDEFAULT NEXTVAL),不能由应用赋值

捕获 DbUpdateConcurrencyException 后必须手动处理冲突

EF Core 不会自动重试或合并。抛出 DbUpdateConcurrencyException 表示:当前实体的并发令牌值与数据库中不一致,即该行已被其他事务修改过。

佳蓝在线销售系统(创业版) 佳蓝在线销售
佳蓝在线销售系统(创业版) 佳蓝在线销售

1、对ASP内核代码进行DLL封装,从而大大提高了用户的访问速度和安全性;2、采用后台生成HTML网页的格式,使程序访问速度得到进一步的提升;3、用户可发展下级会员并在下级购买商品时获得差额利润;4、全新模板选择功能;5、后台增加磁盘绑定功能;6、后台增加库存查询功能;7、后台增加财务统计功能;8、后台面值类型批量设定;9、后台财务曲线报表显示;10、完善订单功能;11、对所有传输的字符串进行安全

下载
  • 异常对象的 Entries 属性包含所有冲突的 EntityEntry,可用来获取原始值、数据库当前值和当前修改值
  • 典型做法是:读取数据库最新值 → 合并业务逻辑 → 更新实体 → 再次调用 SaveChangesAsync
  • 不要简单地 entry.OriginalValues.SetValues(entry.GetDatabaseValues()) 就重试,这会丢失用户本次修改的语义(比如“库存减1”变成“设为当前库存值”)
try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    foreach (var entry in ex.Entries)
    {
        var databaseValues = await entry.GetDatabaseValuesAsync();
        if (databaseValues == null)
        {
            throw new InvalidOperationException("数据库中已不存在该记录");
        }

        // 比如只允许更新 Price,保留 Name 和 RowVersion 来自数据库
        entry.OriginalValues["Price"] = databaseValues["Price"];
        entry.OriginalValues["RowVersion"] = databaseValues["RowVersion"];
    }

    // 重试(注意:需确保业务逻辑幂等,否则可能重复扣款等)
    await context.SaveChangesAsync();
}

高并发下单纯重试容易引发雪崩,要加限流和退避

大量请求同时撞上同一行(如秒杀商品库存),反复重试会导致数据库压力陡增、响应延迟飙升,甚至线程池耗尽。

  • 避免无限制循环重试,应设置最大重试次数(如 3 次)和指数退避(如 10ms → 30ms → 100ms)
  • 热点数据(如库存、账户余额),考虑改用数据库原生命令(UPDATE ... WHERE version = @old AND stock >= @needed)+ 返回影响行数判断成败,绕过 EF Core 的跟踪开销
  • 更彻底的解法是分离读写:用 Redis 做库存预占,再异步落库,把 EF Core 的并发压力转移到缓存层

真正难的不是捕获异常,而是判断“这次冲突要不要让用户重试”“哪些字段允许被覆盖”“失败后该提示什么”,这些都得贴着业务规则来设计,而不是套个 RetryAttribute 就完事。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

683

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

323

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

348

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1096

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

358

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

697

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

577

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

419

2024.04.29

html编辑相关教程合集
html编辑相关教程合集

本专题整合了html编辑相关教程合集,阅读专题下面的文章了解更多详细内容。

38

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.9万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 805人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号