Net6 EfCore CodeFirst 乐观锁 RowRersion
十年河东,十年河西,莫欺少年穷
学无止境,精益求精
1、新建带有RowRersion的实体
/// <summary> ///房子 -- 用于演示抢房子 /// </summary> public class House { public string HouseId { get; set; } public string HouseName { get; set; } public string Onwer { get; set; } public int HouseCount { get; set; } public DateTime? CreateTime { get; set; } public byte[] RowRersion { get; set; } }
2、配置乐观锁令牌,并加入DbSet
public class HouseConfig : IEntityTypeConfiguration<House> { public void Configure(EntityTypeBuilder<House> builder) { builder.ToTable("T_House"); //表名 builder.HasKey(A => A.HouseId);//主键 builder.Property(A => A.HouseId).HasMaxLength(50); builder.Property(A => A.RowRersion).IsRowVersion();//乐观锁令牌 } } public class wechatDbContext : DbContext { public DbSet<House> Houses { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder);//;MultipleActiveResultSets=true optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=demo1;Integrated Security=True;MultipleActiveResultSets=true"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //从当前程序集命名空间加载所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
3、通过指令更新数据库 并在数据库插入测试数据
Add-Migration initHouse
update-database
插入数据
insert into [demo1].[dbo].[T_House]([HouseId],[Onwer],[HouseCount],[CreateTime]) values(newid(),'河南建业',10,getdate())
4、书写测试代码
using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace EfCore { internal class Program { static int hourseCount = 0; static void Main(string[] args) { for (int i = 1; i < 101; i++) { Task.Run(() => { GetHouse(); }); } Thread.Sleep(20000);//20秒执行时间 // Console.WriteLine($"总共{hourseCount}人抢房成功"); Console.Read(); } static void GetHouse() { using (wechatDbContext context = new wechatDbContext()) { var house = context.Houses.FirstOrDefault(A => A.Onwer == "河南建业"); if (house.HouseCount > 0) { house.HouseCount = house.HouseCount - 1; try { context.SaveChanges(); hourseCount++; } catch (DbUpdateConcurrencyException ex) { //Console.WriteLine("数据库访问并发冲突"); //var entity = ex.Entries.FirstOrDefault(); //string newValue = entity.GetDatabaseValues().GetValue<string>("Onwer"); //Console.WriteLine($"您没能抢到该房子,房子已被{newValue}抢走"); } } } } } }
通过 DbUpdateConcurrencyException Laura捕获数据库并发异常
通过异步模仿并发抢房场景
5、测试如下
如果不加乐观锁,脏读误读的情况下,有可能会出现10人以上抢房成功,在此就不做演示了。
@天才卧龙的伯克利