什么是乐观并发控制?

乐观并发控制是一种处理并发访问的数据的方法,它基于一种乐观的假设,即认为并发访问的数据冲突的概率很低。在乐观并发控制中,系统不会立即对并发访问的数据进行加锁,而是在数据被修改时,再检查是否有其他并发操作已经修改了数据。如果检测到冲突,系统 再采取相应的措施来解决冲突。

EF Core 内置了使用并发令牌列实现的乐观并发控制,所谓的并发令牌列通常就是被并发操作影响的列。请看本文是如何在 EF Core 中使用乐观并发控制的……

使用步骤

  1. 创建一个 Asp.net console 项目,并从 Nuget 引用 EF 相关的包

    Microsoft.EntityFrameworkCore.SqlServer

    Microsoft.EntityFrameworkCore.Tools

  2. 配置并发冲突列

    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Metadata.Builders; class HouseConfig : IEntityTypeConfiguration<House>
    {
    public void Configure(EntityTypeBuilder<House> builder)
    {
    builder.ToTable("T_Houses");
    builder.Property(p => p.Name).IsUnicode().IsRequired();
    // 把 Owner 列配置为并发令牌
    builder.Property(p => p.Owner).IsConcurrencyToken();
    }
    }
  3. 在 Program.cs 编写以下代码:

    using Microsoft.EntityFrameworkCore;
    
    Console.WriteLine("请输入您的姓名");
    string name = Console.ReadLine()!;
    using TestDbContext ctx = new TestDbContext(); // 1.获取数据
    var h1 = await ctx.Houses.SingleAsync(h => h.Id == 1);
    if (string.IsNullOrEmpty(h1.Owner))
    {
    // 2.延迟5秒,方便测试
    await Task.Delay(5000); // 3.更新数据
    h1.Owner = name;
    try
    {
    await ctx.SaveChangesAsync();
    Console.WriteLine("抢到手了");
    }
    catch(DbUpdateConcurrencyException ex)
    {
    // 4. 捕捉和处理并发冲突
    var entry = ex.Entries.First();
    var dbValues = await entry.GetDatabaseValuesAsync();
    string newOwner = dbValues.GetValue<string>(nameof(House.Owner));
    Console.WriteLine($"并发冲突,被{newOwner}提前抢走了");
    }
    }
    // 5.处理数据已存在情况
    else
    {
    if (h1.Owner == name)
    {
    Console.WriteLine("这个房子已经是你的了,不用抢");
    }
    else
    {
    Console.WriteLine($"这个房子已经被{h1.Owner}抢走了");
    }
    }
    Console.ReadLine();
  4. 测试

    1. 清理 T_Houses 表数据,让 Owner 列等于 null
    2. 同时运行两个控制台程序
    3. 在第一个控制台程序输入 Tom 并运行
    4. 在第二个控制台程序输入 Jim 并运行
    5. 第一个控制台返回消息:抢到手了
    6. 第二个控制台则返回消息:并发冲突,被Tom提前抢走了

扩展

  1. 通常可以通过把并发修改的属性设置为并发令牌的方式启用乐观并发控制。

  2. 有时候无法确定到底哪个属性适合作为并发令牌,比如程序在不同的情况下会更新不同的列或者程序会更新多个列,在这种情况下,可以使用设置一个额外的并发令牌属性的方式来使用乐观并发控制。

  3. 如果使用Microsoft SQL Server数据库,可以用一个byte[]类型的属性作为并发令牌属性,然后使用IsRowVersion把这个属性设置为RowVersion类型,这个属性对应的数据库列就会被设置为ROWVERSION类型。对于ROWVERSION类型的列,在每次插入或更新行时,Microsoft SQL Server会自动为这一行的ROWVERSION类型的列生成新值。

    1. 增加一个额外的byte[]类型的属性
    class House
    {
    public long Id { get; set; }
    public string Name { get; set; }
    public string? Owner { get; set; }
    public byte[] RowVer { get; set; }
    } 2. 配置并发令牌
    builder.ToTable("T_Houses");
    builder.Property(h => h.Name).IsUnicode();
    builder.Property(h => h.RowVer).IsRowVersion(); 3. Update 语句中的 Where 中使用 RowVer 列
  4. 其它数据库也可以使用 Guid 作为并发令牌控制

  5. 乐观并发控制能够避免悲观锁带来的性能下降、死锁等问题,推荐使用乐观并发控制而不是悲观锁

如何在 EF Core 中使用乐观并发控制的更多相关文章

  1. 文章翻译:ABP如何在EF core中添加数据过滤器

    原文地址:https://aspnetboilerplate.com/Pages/Documents/Articles%5CHow-To%5Cadd-custom-data-filter-ef-cor ...

  2. EF Core中的多对多映射如何实现?

    EF 6.X中的多对多映射是直接使用HasMany-HasMany来做的.但是到了EF Core中,不再直接支持这种方式了,可以是可以使用,但是不推荐,具体使用可以参考<你必须掌握的Entity ...

  3. 9.翻译系列:EF 6以及EF Core中的数据注解特性(EF 6 Code-First系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/dataannotation-in-code-first.aspx EF 6 Code-F ...

  4. 如何在EF Core 使用存储过程

    使用EF Core框架能快速的帮助我们进行常规的数据处理和项目开发,但是ORM虽然好用,但是在许多复杂逻辑的数据处理时,我个人还是偏向用SQL和存储过程的方式去处理,但是研究了一下目前最新版本的EF ...

  5. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

  6. [小技巧]EF Core中如何获取上下文中操作过的实体

    原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html 作者:Lamond Lu 源代码:https://github.com/lamondlu/EFC ...

  7. EF Core中避免贫血模型的三种行之有效的方法(翻译)

    Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...

  8. EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery

    一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...

  9. EF Core中DbContext可以被Dispose多次

    我们知道,在EF Core中DbContext用完后要记得调用Dispose方法释放资源.但是其实DbContext可以多次调用Dispose方法,虽然只有第一次Dispose会起作用,但是DbCon ...

  10. 9.4 翻译系列:EF 6以及 EF Core中的NotMapped特性(EF 6 Code-First系列)

    原文链接:http://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-f ...

随机推荐

  1. odoo17.0 快递鸟模块

    快递鸟是国内使用较为广泛的快递集成查询平台之一,提供了600+的物流公司对接接口,是比较不错的物流查询服务选择.随着odoo17.0的发布,我们最近也将快递鸟模块升级到了17.0.下面我们来详细看一下 ...

  2. Azure - 机器学习企业级服务概述与介绍

    Azure 机器学习 - 为端到端机器学习生命周期使用企业级 AI 服务. 关注TechLead,分享AI全维度知识.作者拥有10+年互联网服务架构.AI产品研发经验.团队管理经验,同济本复旦硕,复旦 ...

  3. [ABC309G] Ban Permutation

    Problem Statement Find the number, modulo $998244353$, of permutations $P=(P_1,P_2,\dots,P_N)$ of $( ...

  4. easycom自动导入自定义组件

    使用时要先创建一个这样的结构 相当于定义一个方法,所有的页面引用就可以了

  5. 如何对连续型数据进行离散化处理,并进行OneHot编码?

    如何对连续型数据进行离散化处理,并进行OneHot编码,最终将OneHot编码作为特征因子输入模型? 什么是OneHot编码 One-Hot编码是分类变量作为二进制向量的表示.这首先要求将分类值映射到 ...

  6. flask的cookie和session会话保持

    Cookie 获取请求cookie 通过请求对象中的cookies属性可以获取cookie. 实例: from flask import Flask, request @app.route(" ...

  7. 华企盾DSC编辑文件不加密常见问题

    1.先查看客户端日志主进程是否是加密进程.日志中是不是勾选智能半透明.加密类型是否有添加 2.用procmon监控保存的文件找出writefile的进程是否有添加,进程树是否有父进程,加密类型是否正确 ...

  8. 浅谈JSP中forward和redirect

    redirect 重定向,完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接 forward 转向,浏览器中不会显示后面的网址;如果你需要在下一个页面中能从中获取新的信息的话,你可以Reques ...

  9. 《最新出炉》系列初窥篇-Python+Playwright自动化测试-36-处理web页面定位toast-下篇

    1.简介 按理说,现在这种一闪而过的toast的已经相当普及或者是见怪不怪了,应该网上的大网站会用到的,偶然的在一次租房中,看到了这种场景,所以宏哥决定将其拿来主义,进行演示实践一下. 2.租房网站 ...

  10. 这些 git 高级命令你知道几个

    大家好,我是 dom 哥.今天给大家分享几个 git 的高级应用. git 是目前最流行的版本控制工具.git 玩的 6 不 6,轻则影响自己的开发幸福指数 ,重则影响下班时间 .本文介绍一些日常开发 ...