1、高并发的情况,时常会发生数据不稳定的情况

  在看本节内容之前,请先看上一章SqlServer 高并发的情况下,如何利用锁保证数据的稳定性

  本节内容,也是具体讨论如何在EF中实现这些操作

2、场景模拟,同上一章,抢券

  EF 不考虑高并发的情况下,抢券代码为:

  1. string _currOwner = Console.ReadLine();//当前用户
  2. using var ctx = new MyDBContext();
  3. var cop = ctx.Coupons.Single(x => x.Id == 2);
  4. if (!string.IsNullOrEmpty(cop.Owner))
  5. {
  6. Console.WriteLine($"券被抢了");
  7. }
  8. else
  9. {
  10. cop.Owner = _currOwner;
  11. Thread.Sleep(5000);
  12. ctx.SaveChanges();
  13. Console.WriteLine($"恭喜{_currOwner}抢到券{cop.Id}了");
  14. }
  15. Console.ReadLine();

  打开两个进程,让tom和jerry同时先后进行抢券,模拟出一个券同时被两个用户抢到的情况

     

  上图可用直观看出,都提示抢券成功,但是owner是晚一点点执行update的jerry,在实际生产中,无法给tom一个交代

3、解决并发问题

  3.1 通过updlock,悲观并发控制

  1. string _currOwner = Console.ReadLine();//当前用户
  2. using var ctx = new MyDBContext();
  3. using var tx = ctx.Database.BeginTransaction();
  4. FormattableString sql = $@"select * from Coupons with(updlock) where id=2";
  5. var cop = ctx.Coupons.FromSqlInterpolated(sql).Single();
  6. if (!string.IsNullOrEmpty(cop.Owner))
  7. {
  8. Console.WriteLine($"券被抢了");
  9. }
  10. else
  11. {
  12. cop.Owner = _currOwner;
  13. Thread.Sleep(5000);
  14. ctx.SaveChanges();
  15. Console.WriteLine($"恭喜{_currOwner}抢到券{cop.Id}了");
  16. }
  17. tx.Commit();
  18. Console.ReadLine();

  解决:但这个是排他锁,有可能造成线程卡顿问题

    

  3.2 通过定义鉴权字段,乐观并发控制

    CouponConfig添加配置

  1. builder.Property(x => x.Owner).IsConcurrencyToken();

    抢券代码:

  1. string _currOwner = Console.ReadLine();//当前用户
  2. using var ctx = new MyDBContext();
  3. var cop = ctx.Coupons.Single(x => x.Id == 2);
  4. if (!string.IsNullOrEmpty(cop.Owner))
  5. {
  6. Console.WriteLine($"券被抢了");
  7. }
  8. else
  9. {
  10. Thread.Sleep(5000);
  11. try
  12. {
  13. cop.Owner = _currOwner;
  14. await ctx.SaveChangesAsync();
  15. Console.WriteLine($"恭喜{_currOwner}抢到券{cop.Id}了");
  16. }
  17. catch (DbUpdateConcurrencyException ex)
  18. {
  19. var entry = ex.Entries.First();
  20. var dbValues = entry.GetDatabaseValues();
  21. var newOwner = dbValues.GetValue<string>(nameof(Coupon.Owner));
  22. Console.WriteLine($"并发冲突,{newOwner}已经抢到该券了");
  23. }
  24. }

    结果:

      

    根据update语句,可用看出where加了owner=旧值,来判断是否发生过更改

  3.3 添加数据版本标识

    如果无法定义一个明确的鉴权字段,那么可用通过新增一个字段,来标识数据来进行鉴权

  1. public class Coupon
  2. {
  3. public int Id { get; set; }
  4. public string Name { get; set; }
  5. public string? Description { get; set; }
  6. public string? Owner { get; set; }
  7. public byte[] RowVersion { get; set; } #迁移到数据库,类型为rowversion,当数据更新时,版本会自动递增
  8. }

    迁移后数据库表代码

  1. CREATE TABLE [dbo].[Coupons] (
  2. [Id] INT IDENTITY (1, 1) NOT NULL,
  3. [Name] NVARCHAR (MAX) NOT NULL,
  4. [Description] NVARCHAR (MAX) NULL,
  5. [Owner] NVARCHAR (MAX) NULL,
  6. [RowVersion] ROWVERSION NOT NULL,
  7. CONSTRAINT [PK_Coupons] PRIMARY KEY CLUSTERED ([Id] ASC)
  8. );

    CouponConfig添加配置

  1. builder.Property(x => x.RowVersion).IsRowVersion();

    抢券代码同3.2

    结果:

  

  理论和3.2相同,where会做一个rowversion的旧值判断

  总结:这三种方法由浅入深,各有利弊,在并发量不大的情况下使用3.1,并发量较大的情况下使用3.2&3.3

  感谢关注!!

  

EF Code 如何应对高并发的更多相关文章

  1. Memcached笔记——(四)应对高并发攻击【转】

    http://snowolf.iteye.com/blog/1677495 近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最 ...

  2. SpringCloud应对高并发的思路

    一.Eureka的高可用性 Eureka下面的服务实例默认每隔30秒会发送一个HTTP心跳给Eureka,来告诉Eureka服务还活着,每个服务实例每隔30秒也会通过HTTP请求向Eureka获取服务 ...

  3. 《即时消息技术剖析与实战》学习笔记10——IM系统如何应对高并发

    一.IM 系统的高并发场景 IM 系统中,高并发多见于直播互动场景.比如直播间,在直播过程中,观众会给主播打赏.送礼.发送弹幕等,尤其是明星直播间,几十万.上百万人的规模一点也不稀奇.近期随着武汉新型 ...

  4. Memcached笔记——(四)应对高并发攻击

    近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Mis ...

  5. 【Redis】1、Jedis对管道、事务以及Watch的操作来应对高并发

    对于一个互联网平台来说,高并发是经常会遇到的场景.最有代表性的比如秒杀和抢购.高并发会出现三个特点: 1.高并发读取 2.高并发写入(一致性) 3.出现超卖问题 前端如何应对? 1.缓存静态数据,例如 ...

  6. 基于tomcat为了应对高并发模型实现webserver

    在博客上,一个简单的AIOweb来样加工.查看AIO异步处理,依靠操作系统完成IO操作Proactor处理模型确实很强大,它可以实现高并发.高响应server一个很好的选择,但在tomcat中间con ...

  7. Linux下配置tomcat+apr+native应对高并发

    摘要:在慢速网络上Tomcat线程数开到300以上的水平,不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,Tomcat将以JNI的形式调用Apache HTTP服 ...

  8. (转)Linux下配置tomcat+apr+native应对高并发

    摘要:在慢速网络上Tomcat线程数开到300以上的水平,不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,Tomcat将以JNI的形式调用Apache HTTP服 ...

  9. Nginx优化配置,轻松应对高并发

    Nginx现在已经是最火的web服务器之一,尤其在静态分离和负载均衡方面,性能十分优越.接下来我们主要看下Nginx在高并发环境下的优化配置,主要是针对 nginx.conf 文件的属性设置.我们打开 ...

  10. php怎样应对高并发

    高并发下的数据安全 我们知道在多线程写入同一个文件的时候,会出现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的). 如果是M ...

随机推荐

  1. ubuntu64运行32位程序安装过程

    Ubuntu运行32位程序可以使用如下方法: 第一步: 确认你有一个64位架构的内核 你可以打开终端然后输入: dpkg --print-architecture 你将会看到像下面这样的内容: amd ...

  2. Java执行cmd命令工具类

    工具类: public class CmdTask implements Runnable { private String command; private String dirPath; publ ...

  3. 解决vuex“状态管理声明输错”后报错为:"Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_1_vuex__.a.store is not a constructor"

    //Vuex index.js 源码 import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); import actions fro ...

  4. mysql-列拆分

    tableA id warehouse_id 1 1,2 想要的结果: id warehouse_id 1 1 2 2 select *(其他的字段), substring_index(substri ...

  5. 证书profile 申请

    ios  云打包   证书 和密码  在之前的笔记当中已申请好 证书profile 文件申请 登录苹果开放平台 申请前要添加身份,设备,设备那需要填写udid 方法链接https://www.jian ...

  6. Windows Powershell个性化设置

    1. 设置Powershell prompt只显示当前目录: 2. 设置Powershell title为当前路径: 这个文件的路径为:echo $profile # file location:ec ...

  7. CeiT:Incorporating Convolution Designs into Visual Transformers

    CeiT:Incorporating Convolution Designs into Visual Transformers 将CNN提取low-level特征,强化局部特征提取的能力,与Trans ...

  8. 10s后再次获取手机验证码

    一般手机验证码获取都会加个间隔时间 js代码如下: function getDxCode(btn){ var reg = /^1[3|4|5|7|8][0-9]{9}$/; //验证规则 var mo ...

  9. Python+Django(4)——创建其他网页(模板继承)

    模板继承: 1,修改主页 父模板:抽取通用元素,在index.html同级目录下新建base.html <p> <a href="{% url 'learning_logs ...

  10. 学习JavaScript第一周

    三种输出方式,console.log.element.write.alert(): 简单数据类型:数值型.字符串型.布尔类型.undefined.null 复杂数据类型:对象 数据类型的转换:字符串转 ...