如何在 EF Core 中使用乐观并发控制

简介: 如何在 EF Core 中使用乐观并发控制

什么是乐观并发控制?

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

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.乐观并发控制能够避免悲观锁带来的性能下降、死锁等问题,推荐使用乐观并发控制而不是悲观锁


相关文章
|
19天前
|
存储 关系型数据库 MySQL
MySQL MVCC全面解读:掌握并发控制的核心机制
【10月更文挑战第15天】 在数据库管理系统中,MySQL的InnoDB存储引擎采用了一种称为MVCC(Multi-Version Concurrency Control,多版本并发控制)的技术来处理事务的并发访问。MVCC不仅提高了数据库的并发性能,还保证了事务的隔离性。本文将深入探讨MySQL中的MVCC机制,为你在面试中遇到的相关问题提供全面的解答。
55 2
|
4月前
|
SQL 算法 关系型数据库
(十)全解MySQL之死锁问题分析、事务隔离与锁机制的底层原理剖析
经过《MySQL锁机制》、《MySQL-MVCC机制》两篇后,咱们已经大致了解MySQL中处理并发事务的手段,不过对于锁机制、MVCC机制都并未与之前说到的《MySQL事务机制》产生关联关系,同时对于MySQL锁机制的实现原理也未曾剖析,因此本篇作为事务、锁、MVCC这三者的汇总篇,会在本章中补全之前空缺的一些细节,同时也会将锁、MVCC机制与事务机制之间的关系彻底理清楚。
|
5月前
|
存储 SQL 关系型数据库
【MySQL技术内幕】6.5-锁问题、阻塞、死锁、锁升级
【MySQL技术内幕】6.5-锁问题、阻塞、死锁、锁升级
170 2
|
6月前
|
关系型数据库 MySQL 中间件
【MySQL实战笔记】07 | 行锁功过:怎么减少行锁对性能的影响?-02 死锁和死锁检测
【4月更文挑战第19天】在高并发环境下,死锁发生在多个线程间循环等待资源时,导致无限期等待。MySQL中,死锁可通过`innodb_lock_wait_timeout`参数设置超时或`innodb_deadlock_detect`开启死锁检测来解决。默认的50s超时可能不适用于在线服务,而频繁检测会消耗大量CPU。应对热点行更新引发的性能问题,可以暂时关闭死锁检测(风险是产生大量超时),控制并发度,或通过分散记录减少锁冲突,例如将数据分拆到多行以降低死锁概率。
173 1
|
6月前
|
SQL 关系型数据库 MySQL
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
MySQL事务原理分析(ACID特性、隔离级别、锁、MVCC、并发读异常、并发死锁以及如何避免死锁)
161 1
|
存储 SQL NoSQL
掌控MySQL并发:深度解析锁机制与并发控制
本文详尽地探索了MySQL中处理并发事务的各种方式,从基础的锁机制到高级的MVCC,从行锁到表锁,从读操作到写操作。我们将深入解析隐式锁、插入意向锁和其他类型的锁在MySQL并发控制中的作用,以及如何在各种场景中使用这些锁机制来保证数据的一致性和事务的并发性。
414 1
掌控MySQL并发:深度解析锁机制与并发控制
|
关系型数据库 MySQL 数据库
请解释MySQL中的锁机制,包括共享锁和排他锁的概念和区别。
MySQL中的锁机制是用于管理并发访问数据库的一种技术。通过使用锁,可以确保在同一时间只有一个用户或进程能够对数据进行读取或修改,以避免数据冲突和不一致性。
|
SQL 安全 算法
精通Java事务编程(7)-可串行化隔离级别之两阶段锁定(2PL,two-phase locking)
近30年,DB只有一种广泛使用的串行化算法:两阶段加锁 1 2PL不是2PC 请注意,虽然两阶段锁定(2PL)听起来非常类似于两阶段提交(2PC),但是完全不同概念
227 0
|
SQL 存储 程序员
SQL Server 锁机制 悲观锁 乐观锁 实测解析
SQL Server 锁机制 悲观锁 乐观锁 实测解析
172 0
SQL Server 锁机制 悲观锁 乐观锁 实测解析
|
NoSQL Redis 开发者
事务-死锁解决方案|学习笔记
快速学习事务-死锁解决方案