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 ...
随机推荐
- 【2020NIO.AC省选模拟#10】C. 寄蒜几盒
题目链接 原题解: 可以发现,假设我们把凸多边形看做障碍,一个点没有被染色当且仅当在它的位置上能看到凸多边形任意两条相对的边中的一条(也就是能看到至少$\dfrac{n}{2}$条边). 对于每个询问 ...
- MATLAB 多行注释
自用的两种方法 1: %{ 若干语句 } % 2.快捷键CTRL+R,取消注释CTRL+T
- gcc的编译过程
1. 预处理,生成 .i 的文件.(input) 2. 将 .i的文件转换成汇编语言,生成 .s 的文件 3.生成机器语言文件,.o的文件 4.连接目标代码,生成可执行文件 .out
- pycharm导入第三方包
- 解决IOS上传竖向照片会旋转90度的问题
// 解决IOS上传竖向照片会旋转90度的问题 rotate() { const that = this; that.imgOrientation = 1; let Orientation = nul ...
- Vuex----Actions
Actions用于处理异步任务. 如果通过异步操作变更数据,必须通过 Action,而不能使用Mutation,但是在 Action中还是要通过触发Mutation的方式间接变更数据. 注意: 在Ac ...
- C语言初级阶段6——自定义数据类型
C语言初级阶段6--自定义数据类型 阐述 1.构造数据类型:用户自己建立的数据类型(自定义数据类型). 2.C语言中的自定义数据类型:数组类型.结构体类型.共用体类型和枚举类型. 结构体 1.定义:C ...
- Java中StringBuilder相关知识点
StringBuilder 1.StringBuilder概述 如果对字符串进行拼接操作,每次拼接都会构建一个新的String对象,既耗时又浪费空间,而且这种操作还不可避免.我们可以通过StringB ...
- pip 临时切换 国内源
sudo pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
- Testlink for linux by Xampp
Testlink 1.环境: (1)需要的环境配置: ①Linux system. ②Mysql ③apache ④Php (2)上面的2,3,4我们使用简易的Xamppp集成的环境,下面是安装配置x ...