EF Core – 乐观并发
前言
之前写过 EF Core 悲观并发, 这篇主要讲一下乐观并发.
乐观并发的机制可以看这篇.
Why Need This?
如果你用 EF Core 做数据管理, 建议你每个 Entity 都配置乐观并发.
因为 EF 的机制是这样的. 先把资料读出来, 然后修改资料, 然后 SaveChanges.
这个 SaveChanges 并不会把所有的资料都放入 update 语句中, 它会依据之前拿出来的资料做 compare, 如果发现值不同才会生产语句.
由于有了这个"依赖读的资料做逻辑判断" 所以就会有并发的问题了.
比如读出来的数据是 columnA = value1
间中有人把 value1 换成 value2
SaveChange 的时候, 由于我们没有修改 columnA 所以 EF Core 不会生产语句 set columnA = value1
所以哪怕我是在另一个人之后做了 update, 但是数据库这时并不是我以为的 value1. (我们的逻辑告诉我们, entity save changes 之后, 数据库资料 should be 和我的 entity 一样阿)
为了解决这样的混乱, 做一个乐观并发就可以了
主要参考
Handling Concurrency Conflicts
ConcurrencyToken vs RowVersion
RowVersion vs ConcurrencyToken In EntityFramework/EFCore
RowVersion
在 Entity 加入 RowVersion Property
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
public byte[] RowVersion { get; set; } = null!;
}
Setup Model
modelBuilder.Entity<Product>().Property(e => e.RowVersion).IsRowVersion();
执行
var product = db.Products.AsTracking().First();
product.Name = "New Product Name";
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
}
运行的语句多了一个 Where RowVersion = old row version value

如果间中有人对这个 row 做了修改 (不管是谁修改的, 哪怕是 SQL Trigger 改了这个 row, row version 都会自动 update)
那么这个 update 就会失败记入 catch.
题外话: SQL Server 的 RowVersion 使用 binary 维护的, 它不是时间概念, 也不是数据 hash, 它就是一个 running number. 只要 insert/update 语句执行它就会改变 (哪怕没有任何 value change).
IsConcurrencyToken
Entity
public int MyRowVersion { get; set; }
Model
modelBuilder.Entity<Product>().Property(e => e.MyRowVersion).IsConcurrencyToken();
执行
var product = db.Products.AsTracking().First();
product.Name = "New Product Name";
try
{
product.MyRowVersion++; // 手动 update
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
}
语句

和 RowVersion 区别
整个机制是一样的, 唯一的区别是 ConcurrencyToken 需要自己手动维护, SQL Server 不会在 insert/update 的时候自动去更新这个 row version 的 column.
另外 EF Core 不鼓励我们用 ConcurrencyToken 哦

当 RowVersion 遇上 Trigger
上面我们有说, 如果数据库有 trigger 的话, 我们在 EF 就无法同时修改 2 个 Entity,
比如我修改了 Entity A 和 Entity B, 然后 SaveChanges
当运行 update A table 的时候 trigger 触发了, 然后它去 update 了 B
导致 B 的 row version 被修改了
然后 EF 跑下一句 update Entity B 语句, 加上 RowVersion = old value 就直接失败了.
解决方法有 2 个思路
1. 不要在一个 SaveChanges 里同时修改 2 个有 Trigger 关系的 Entity, 一个一个修改, 确保拿到最新的 RowVersion, 或者你的顺序要正确.
2. 使用 ConcurrencyToken, 自己决定什么时候需要 update row version, 比如 trigger 的时候不更新. 只有 EF Core SaveChanges 才更新.
目前看 2 个方案都都不理想.
第一个就是要 take care of 这种同时 update 多个 entity 在一个 SaveChanges 里的情况, 简单说就完全不要这样子做, 坚持 1 个 1 个 update, 因为即使现在没有 trigger, 但是也可能后来加入 trigger.
那以后还是有报错的可能性. 总不能等报错才 fix, 也不能加 trigger 的时候全场找这种情况.
第二个也很糟, 因为 trigger 不更新 row version 意味着, 在 EF 如果我们想利用乐观并发就要注意, 不可依赖 Trigger 会更新的 column, 比如冗余数据.
因为它没有 RowVersion 的保护, 要依赖就要使用 transaction. 这个写起来不算难, 但如果 miss 掉的话, 它不会报错. 这个挺危险. 一不小心数据就逻辑错了. 比报错还糟糕.
而且还得另外维护一套自己 update row version 的机制.
追根究底就是 EF 和 Trigger 八字不合, 所以就会遇到很多风水的问题咯.
目前我会选择第 2 个解决方案, 因为 2 个都不好,但是第一个影响的范围会比较大,出现的机率也比较高, 第二个出现的机率比较小, 只是要非常小心, 走一步看一步先吧.
EF Core – 乐观并发的更多相关文章
- EntityFramework Core高并发深挖详解,一纸长文,你准备好了吗?
前言 之前有关EF并发探讨过几次,但是呢,博主感觉还是有问题,为什么会觉得有问题,其实就是理解不够透彻罢了,于是在项目中都是用的存储过程或者SQL语句来实现,利用放假时间好好补补EF Core并发的问 ...
- EF|CodeFirst数据并发管理
在项目开发中,我们有时需要对数据并发请求进行处理.举个简单的例子,比如接单系统中,AB两个客服同时请求处理同一单时,应该只有一单请求是处理成功的,另外一单应当提示客服,此单已经被处理了,不需要再处理. ...
- EF Core下利用Mysql进行数据存储在并发访问下的数据同步问题
小故事 在开始讲这篇文章之前,我们来说一个小故事,纯素虚构(真实的存钱逻辑并非如此) 小刘发工资后,赶忙拿着现金去银行,准备把钱存起来,而与此同时,小刘的老婆刘嫂知道小刘的品性,知道他发工资的日子,也 ...
- 笔记-EF Core 并发冲突与令牌
并发标记并发分悲观并发和乐观并发.悲观并发:比如有两个用户A,B,同时登录系统修改一个文档,如果A先进入修改,则系统会把该文档 锁住,B就没办法打开了,只有等A修改完,完全退出的时候B才能进入修改.乐 ...
- EF+MySQL乐观锁控制电商并发下单扣减库存,在高并发下的问题
下订单减库存的方式 现在,连农村的大姐都会用手机上淘宝购物了,相信电商对大家已经非常熟悉了,如果熟悉电商开发的同学,就知道在买家下单购买商品的时候,是需要扣减库存的,当然有2种扣减库存的方式, 一种是 ...
- 悲观并发 乐观并发 Entity Framework Core中的并发处理
悲观并发策略 A用户发起一个请求 开启了事务 查询到了某一条数据 进行修改 在A提交事务之前 其他人都不能对这条数据进行修改 这种策略最常见的一个问题就是死锁 比如A修改X记录,B修改Y ...
- EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)
官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞.请大 ...
- [转]EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)
本文转自:http://www.cnblogs.com/VolcanoCloud/p/5572408.html 官方文档英文地址:https://github.com/aspnet/EntityFra ...
- 第四节:EF Core的并发处理
1.说明 和EF版本的并发处理方案一致,需要知道乐观并发和悲观并发的区别,EF Core只支持乐观并发:监控并发的两种方案:监测单个字段和监测整条数据,DataAnnotations 和 Fluent ...
- .NET 云原生架构师训练营(模块二 基础巩固 EF Core 更新和迁移)--学习笔记
2.4.6 EF Core -- 更新 状态 自动变更检测 不查询删除和更新 并发 状态 Entity State Property State Entity State Added 添加 Uncha ...
随机推荐
- TokenObtainPairSerialize
TokenObtainPairSerializer是Django REST framework的SimpleJWT库提供的序列化器.它用于对用户凭据(如用户名和密码)进行序列化和验证,并在成功的身份验 ...
- C#封装HttpClient工具类库(.NET4.5以上)
1.Json字符串实体转换扩展方法,依赖Json.Net包 /// <summary> /// Json扩展方法 /// </summary> public static cl ...
- CF1950B Upscaling题解
CF1950B Upscaling题解 题意 给予你一个正整数 \(n\),构造一个如图的字符矩阵. 思路 注意数据 \(1\le n \le 20\),可以发现数据很小,于是我们可以暴力模拟. 我们 ...
- postfix&dovecot搭建邮件服务器
本篇参考 https://blog.51cto.com/5001660/2377785和小翔博客https://www.liuyixiang.com/post/113927.html. 邮件发送和接受 ...
- web3产品介绍:mask将Web3的隐私和优势引入像Facebook和Twitter这样的社交媒体平台
介绍: Mask Network是一个开源的浏览器扩展,将Web3的隐私和优势引入像Facebook和Twitter这样的社交媒体平台.它是一个功能强大的工具,允许用户在社交媒体上享受区块链的隐私保护 ...
- 11、Git之自建项目托管平台(GitLab极狐)
11.1.简介 Github 是国外的项目托管平台,由于网络问题,在国内访问和使用不是很方便. Gitee 是国内的项目托管平台,虽然在访问和使用上挺方便的,但依然让人担忧项目代码可能会被泄露. 因此 ...
- 论文写作:“et al.”和“etc.”在英语中的区别
"et al."和"etc."在英语中有不同的用法和含义.以下是它们的区别和具体用法: et al. "et al."是拉丁短语" ...
- 什么是智慧城市(Smart City)?
Smart City是一个常见的概念,但是这个东西,这个名词到底指代的是什么却一直搞不太清,于是就查了查资料,有了这篇blog. 参考: https://baijiahao.baidu.com/s?i ...
- 在docker容器中创建用户组和用户,并且多用户共用一个anaconda环境
背景: 实验室可以使用一个浪潮的AI计算平台,该平台运行的都是docker容器,并且不能联网,因此谁要是想要安装什么软件的话就需要自己单独打包镜像到平台上,大致步骤为: 1. 在平台的镜像管理中找 ...
- 多网卡系统下如何使用tcp协议实现MPI的分布式多机运行(mpi的实现使用openmpi)
如题: 最近在看MPI方面的东西,主要是Python下的MPI4PY,学校有超算机房可以使用MPI,但是需要申请什么的比较麻烦,目的也本就是为了学习一下,所以就想着在自己的电脑上先配置一下. 现有硬件 ...