在 Entity Framework Core 中实现乐观锁

乐观锁是一种并发控制策略,它假设多个事务可以同时进行而不互相干扰,只在提交时检查是否有冲突。在 EF Core 中,可以通过以下几种方式实现乐观锁:

1. 使用并发令牌 (Concurrency Token)

这是 EF Core 推荐的实现乐观锁的方式。

实现步骤:

  1. 在实体类中添加一个并发令牌属性:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    
    // 并发令牌属性
    [Timestamp]
    public byte[] RowVersion { get; set; }
}

或者使用 Fluent API 配置:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .Property(p => p.RowVersion)
        .IsRowVersion();
}
  1. 当更新实体时,EF Core 会自动检查并发令牌:

try
{
    var product = context.Products.Find(1);
    product.Price = 20.99m;
    context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
    // 处理并发冲突
    Console.WriteLine("并发冲突发生!");
}

2. 使用其他属性作为并发令牌

除了 rowversion/timestamp 列,任何属性都可以配置为并发令牌:

public class Order
{
    public int Id { get; set; }
    public string OrderNumber { get; set; }
    
    [ConcurrencyCheck]
    public DateTime LastUpdated { get; set; }
}

或者使用 Fluent API:

modelBuilder.Entity<Order>()
    .Property(o => o.LastUpdated)
    .IsConcurrencyToken();

3. 处理并发冲突

当检测到并发冲突时,EF Core 会抛出 DbUpdateConcurrencyException,你可以捕获并处理它:

try
{
    // 尝试保存
    context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
    foreach (var entry in ex.Entries)
    {
        if (entry.Entity is Product)
        {
            // 获取当前数据库值
            var databaseValues = entry.GetDatabaseValues();
            
            // 获取原始值(用户尝试保存的值)
            var proposedValues = entry.CurrentValues;
            
            // 获取原始值(最初查询的值)
            var originalValues = entry.OriginalValues;
            
            // 根据业务逻辑决定如何处理冲突
            // 例如:合并更改、提示用户等
            
            // 刷新原始值以便下次保存
            entry.OriginalValues.SetValues(databaseValues);
        }
        else
        {
            throw new NotSupportedException(
                "不支持的并发冲突类型: " + entry.Metadata.Name);
        }
    }
    
    // 重试保存
    context.SaveChanges();
}

注意事项

  1. 并发令牌属性会在每次更新时自动更新

  2. 使用 rowversion/timestamp 类型通常是最简单高效的方式

  3. 对于高并发场景,乐观锁比悲观锁性能更好

  4. 需要妥善处理并发冲突,提供良好的用户体验

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值