• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

EF Core 的并发处理

武飞扬头像
哩厚dotNET
帮助2

概念

并发问题是一个常见的问题,很多人认为并发只会发生在数据库操作上,其实不然,它一样可以发生在文件的读写操作上。只要我们从服务器访问资源并更新,就有可能会发生并发。但我们在开发中更多的是连接数据库来操作数据,所以我们习惯性的认为并发是数据库并发。

并发是指两个或多个用户试图同时修改同一资源造成的冲突。比如,A君读取数据以更新数据,但B君在A君更新数据之前先更新数据,A君更新操会导致三个值之间发生冲突。这三个值分别:

  • A君读取到的值(原始值)

  • B君更新的值(数据库值)

  • A君正在更新的值(当前值)

这种并发冲突如果不做任何处理会造成数据前后的不一致和完整性。比如:下单和退货发生并发冲突时将造成库存不一致,后果可想而知。

我们通过并发检测和解决并发冲突称为并发处理。

并发处理是一种机制,使众多用户能够同时访问相同的资源,同时确保资源在未来所有请求中保持数据的安全性、完整性和一致。

处理并发冲突有两种解决方法:乐观并发和悲观并发策略。

悲观并发

悲观并发每次访问资源时都上锁,使得其它用户无法访问该资源。这种策略就是假设用户每次访问资源都认定会更新资源,所以每次访问资源就上锁,当资源被修改时,同一资源上的所有其它并发操作都将被暂停,直到当前操作完成,并且该资源上的锁被释放。

这种方法在资源争用较高的场景中是一个不错的选择。可以在锁定持续时间较短的场景中利用悲观并发。但是,当用户与数据交互时,悲观并发不能很好的扩展,会导致资源锁住很长的时间。再者当互联网连接较弱或断开连接时,将无法正确管理数据,这会影响数据库的工作。

乐观并发

乐观并发假设用户每次访问资源都不会更新资源,所以资源不会被锁定。但是在更新的时候会判断在此期间其它用户是否有更新操作。

乐观并发遵循“保存最新数据”的策略。

乐观并发通常用于数据稀缺的场景,也就是常说的频繁读取,这样可以提高吞吐量,但也会消耗额外的服务器资源 。

乐观并发提高了性能也更好的支持扩展,因为它允许服务器在更短时间内为更多的客户端提供服务。

今天,我们来讨论 EF Core 是怎么处理数据库并发。在EF Core 中是不支持悲观并发,但有两种方式可用于乐观并发来进行并发冲突检测。

一种是将实体配置为并发令牌;另一种是在实体类中添加行版本属性。

使用并发令牌

Data Annotation 配置方式

  1.  
    public class Users
  2.  
    {
  3.  
    public int Id { get; set; }
  4.  
    public string UserName { get; set; }
  5.  
    public string PasswordHash { get; set; }
  6.  
    [ConcurrencyCheck]
  7.  
    public string ConcurrencyStamp { get; set; }
  8.  
    }

Fluent API 配置方式

  1.  
    protected override void OnModelCreating(ModelBuilder modelBuilder)
  2.  
    {
  3.  
    modelBuilder.Entity<Users>()
  4.  
    .Property(p => p.ConcurrencyStamp)
  5.  
    .IsConcurrencyToken();
  6.  
    }

两种配置方式选择一种即可,使用并发令牌 EF Core 不会自动生成值,我们在更新实体记得给 ConcurrencyStamp 赋值。

使用版本属性

Data Annotation 配置方式

  1.  
    public class Roles
  2.  
    {
  3.  
    public int Id { get; set; }
  4.  
    public string Name { get; set; }
  5.  
    public string Description { get; set; }
  6.  
    [Timestamp]
  7.  
    public byte[] Timestamp { get; set; }
  8.  
    }

Fluent API 配置方式

  1.  
    protected override void OnModelCreating(ModelBuilder modelBuilder)
  2.  
    {
  3.  
    modelBuilder.Entity<Roles>()
  4.  
    .Property(p => p.Timestamp)
  5.  
    .IsRowVersion();
  6.  
    }

也是两种选择一种,但与并发令牌不同的是不用给 Timestamp 赋值,EF Core 会自动产生一个值。

配置完之后 ,实体执行更新或删除操作时,EF Core 都会将请求中的信息值与数据库表中的值进行比较。

  • 如果两个值匹配,则执行操作。

  • 如果值不匹配,则更新或删除操作将中止并且抛出一个 DbUpdateConcurrencyException。

当 EF Core 抛出 DbUpdateConcurrencyException ,我们可以做如下选择进行处理:

  • 中止操作并要求用户刷新界面重新操作,称为使用他的,但会覆盖本地的操作数据。

  • 使用当前值(最新一次提交的数据)并尝试重新 SaveChanges ,称为使用我的,但会覆盖服务器上的数据。

  • 将冲突记录下来,让用户自己选择使用那个数据,称为手动解决。这种方式始终保持数据最新。

以下是个简单的冲突处理代码:

  1.  
    using (var context = new ApplicationDbContext())
  2.  
    {
  3.  
    var role = context.Roles.Single(p => p.Id == 1);
  4.  
    role.Name = "administrators";
  5.  
     
  6.  
    context.Database.ExecuteSqlRaw(
  7.  
    "UPDATE dbo.Roles SET Description = '管理员组' WHERE Id = 1");
  8.  
     
  9.  
    var savedData = false;
  10.  
     
  11.  
    while (!savedData)
  12.  
    {
  13.  
    try
  14.  
    {
  15.  
    // 更新到数据库
  16.  
    context.SaveChanges();
  17.  
    savedData = true;
  18.  
    }
  19.  
    catch (DbUpdateConcurrencyException ex)
  20.  
    {
  21.  
    foreach (var item in ex.Entries)
  22.  
    {
  23.  
    if (item.Entity is Roles)
  24.  
    {
  25.  
    var currentValues = entry.CurrentValues;
  26.  
    var dbValues = entry.GetDatabaseValues();
  27.  
     
  28.  
    foreach (var prop in currentValues.Properties)
  29.  
    {
  30.  
    var currentValue = currentValues[prop];
  31.  
    var dbValue = dbValues[prop];
  32.  
    }
  33.  
     
  34.  
    // 刷新原始值以绕过下一次并发检查
  35.  
    item.OriginalValues.SetValues(dbValues);
  36.  
    }
  37.  
    else
  38.  
    {
  39.  
    throw new NotSupportedException( "未处理的并发冲突:" item.Metadata.Name);
  40.  
    }
  41.  
    }
  42.  
    }
  43.  
    }
  44.  
    }
学新通

这个示例只是说明下 DbUpdateConcurrencyException 里的 Entries 及三种值。

EF Core 并发处理就到这。

祝大家学习愉快!

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhiaaggc
系列文章
更多 icon
同类精品
更多 icon
继续加载