EF Code 如何应对高并发
1、高并发的情况,时常会发生数据不稳定的情况
在看本节内容之前,请先看上一章SqlServer 高并发的情况下,如何利用锁保证数据的稳定性
本节内容,也是具体讨论如何在EF中实现这些操作
2、场景模拟,同上一章,抢券
EF 不考虑高并发的情况下,抢券代码为:
string _currOwner = Console.ReadLine();//当前用户
using var ctx = new MyDBContext();
var cop = ctx.Coupons.Single(x => x.Id == 2);
if (!string.IsNullOrEmpty(cop.Owner))
{
Console.WriteLine($"券被抢了");
}
else
{
cop.Owner = _currOwner;
Thread.Sleep(5000);
ctx.SaveChanges();
Console.WriteLine($"恭喜{_currOwner}抢到券{cop.Id}了");
}
Console.ReadLine();
打开两个进程,让tom和jerry同时先后进行抢券,模拟出一个券同时被两个用户抢到的情况

上图可用直观看出,都提示抢券成功,但是owner是晚一点点执行update的jerry,在实际生产中,无法给tom一个交代
3、解决并发问题
3.1 通过updlock,悲观并发控制
string _currOwner = Console.ReadLine();//当前用户
using var ctx = new MyDBContext();
using var tx = ctx.Database.BeginTransaction();
FormattableString sql = $@"select * from Coupons with(updlock) where id=2";
var cop = ctx.Coupons.FromSqlInterpolated(sql).Single();
if (!string.IsNullOrEmpty(cop.Owner))
{
Console.WriteLine($"券被抢了");
}
else
{
cop.Owner = _currOwner;
Thread.Sleep(5000);
ctx.SaveChanges();
Console.WriteLine($"恭喜{_currOwner}抢到券{cop.Id}了");
}
tx.Commit();
Console.ReadLine();
解决:但这个是排他锁,有可能造成线程卡顿问题

3.2 通过定义鉴权字段,乐观并发控制
CouponConfig添加配置
builder.Property(x => x.Owner).IsConcurrencyToken();
抢券代码:
string _currOwner = Console.ReadLine();//当前用户
using var ctx = new MyDBContext();
var cop = ctx.Coupons.Single(x => x.Id == 2);
if (!string.IsNullOrEmpty(cop.Owner))
{
Console.WriteLine($"券被抢了");
}
else
{
Thread.Sleep(5000);
try
{
cop.Owner = _currOwner;
await ctx.SaveChangesAsync();
Console.WriteLine($"恭喜{_currOwner}抢到券{cop.Id}了");
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.First();
var dbValues = entry.GetDatabaseValues();
var newOwner = dbValues.GetValue<string>(nameof(Coupon.Owner));
Console.WriteLine($"并发冲突,{newOwner}已经抢到该券了");
}
}
结果:

根据update语句,可用看出where加了owner=旧值,来判断是否发生过更改
3.3 添加数据版本标识
如果无法定义一个明确的鉴权字段,那么可用通过新增一个字段,来标识数据来进行鉴权
public class Coupon
{
public int Id { get; set; }
public string Name { get; set; }
public string? Description { get; set; }
public string? Owner { get; set; }
public byte[] RowVersion { get; set; } #迁移到数据库,类型为rowversion,当数据更新时,版本会自动递增
}
迁移后数据库表代码
CREATE TABLE [dbo].[Coupons] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NOT NULL,
[Description] NVARCHAR (MAX) NULL,
[Owner] NVARCHAR (MAX) NULL,
[RowVersion] ROWVERSION NOT NULL,
CONSTRAINT [PK_Coupons] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CouponConfig添加配置
builder.Property(x => x.RowVersion).IsRowVersion();
抢券代码同3.2
结果:

理论和3.2相同,where会做一个rowversion的旧值判断
总结:这三种方法由浅入深,各有利弊,在并发量不大的情况下使用3.1,并发量较大的情况下使用3.2&3.3
感谢关注!!
EF Code 如何应对高并发的更多相关文章
- Memcached笔记——(四)应对高并发攻击【转】
http://snowolf.iteye.com/blog/1677495 近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最 ...
- SpringCloud应对高并发的思路
一.Eureka的高可用性 Eureka下面的服务实例默认每隔30秒会发送一个HTTP心跳给Eureka,来告诉Eureka服务还活着,每个服务实例每隔30秒也会通过HTTP请求向Eureka获取服务 ...
- 《即时消息技术剖析与实战》学习笔记10——IM系统如何应对高并发
一.IM 系统的高并发场景 IM 系统中,高并发多见于直播互动场景.比如直播间,在直播过程中,观众会给主播打赏.送礼.发送弹幕等,尤其是明星直播间,几十万.上百万人的规模一点也不稀奇.近期随着武汉新型 ...
- Memcached笔记——(四)应对高并发攻击
近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Mis ...
- 【Redis】1、Jedis对管道、事务以及Watch的操作来应对高并发
对于一个互联网平台来说,高并发是经常会遇到的场景.最有代表性的比如秒杀和抢购.高并发会出现三个特点: 1.高并发读取 2.高并发写入(一致性) 3.出现超卖问题 前端如何应对? 1.缓存静态数据,例如 ...
- 基于tomcat为了应对高并发模型实现webserver
在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间con ...
- Linux下配置tomcat+apr+native应对高并发
摘要:在慢速网络上Tomcat线程数开到300以上的水平,不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,Tomcat将以JNI的形式调用Apache HTTP服 ...
- (转)Linux下配置tomcat+apr+native应对高并发
摘要:在慢速网络上Tomcat线程数开到300以上的水平,不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,Tomcat将以JNI的形式调用Apache HTTP服 ...
- Nginx优化配置,轻松应对高并发
Nginx现在已经是最火的web服务器之一,尤其在静态分离和负载均衡方面,性能十分优越.接下来我们主要看下Nginx在高并发环境下的优化配置,主要是针对 nginx.conf 文件的属性设置.我们打开 ...
- php怎样应对高并发
高并发下的数据安全 我们知道在多线程写入同一个文件的时候,会出现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的). 如果是M ...
随机推荐
- shell_Day01
1.判断/etc/inittab文件是否大于100行,如果大于,则显示"/etc/inittab is a big file."否者显示"/etc/inittab is ...
- mysql设置表名不区分大小写
1.root登录,修改/etc/my.cnf2.在mysqld下加入:lower_case_table_names=13.重新数据库
- vue、react配置gzip打包后,删除源文件deleteOriginalAssets: true,nginx需要的配置
1.删除源文件后,配置了gzip,当配置gzip删除源文件后,解决前端history问题,就会出现所有的都返回html,请求js.css也会返回html,页面会报错,如下配置即可 location / ...
- Python+Django(4)——创建其他网页(模板继承)
模板继承: 1,修改主页 父模板:抽取通用元素,在index.html同级目录下新建base.html <p> <a href="{% url 'learning_logs ...
- puts()与scanf(“%s”)
使用gets()即使字符串中含有空格,依然可以接收,而scanf()不会. Example: /* 输入一个字符串到字符数组s1中,将s1中的字符串复制到字符数组s2中并输出s2中的字符串. 不用st ...
- Using Semaphores in Delphi, Part 2: The Connection Pool
Abstract: Semaphores are used to coordinate multiple threads and processes. That semaphores provide ...
- CentOS 7(Linux)安装Docker
CentOS 7(Linux)安装Docker 一.分别执行下列命令添加并更新yum源 yum update yum install epel-release -y yum clean all yum ...
- C# 高精度定时器
https://blog.gkarch.com/2015/09/high-resolution-timer.html https://www.cnblogs.com/samgk/articles/57 ...
- flowable初体验踩坑及概述
遵守bpmn2.0协议(前提)(还在找比较好用的绘图工具) 可以使用idea插件进行绘图保存成xml进行改造编写 Flowable BPMN visualizer和JBoss jBPM , 暂时使用的 ...
- Cmake 把 CGAL的demo 编译生成 .sln文件 遇到的一些问题
尝试了N个版本后,选择了CGAL5.02 为啥去官网或者github下载的CGAl只是一个库,没有窗口,而这个却有呢 链接:https://pan.baidu.com/s/1TvrWQRc9yYD ...