当前位置:首页 > C# > 正文

EF Core 悲观并发控制详解(C# 中实现事务隔离级别与数据库锁机制)

在多用户并发访问数据库的场景中,如何确保数据的一致性和完整性是开发人员必须面对的问题。Entity Framework Core(简称 EF Core)作为 .NET 平台主流的 ORM 框架,提供了多种并发控制策略。本文将重点讲解 EF Core 悲观并发控制 的实现方式,并深入探讨 C# 事务隔离级别 与数据库锁机制的配合使用,帮助初学者轻松掌握这一关键技能。

EF Core 悲观并发控制详解(C# 中实现事务隔离级别与数据库锁机制) 悲观并发控制  C# 事务隔离级别 Entity Framework 并发处理 数据库锁机制 第1张

什么是悲观并发控制?

悲观并发控制(Pessimistic Concurrency Control)假设多个用户很可能同时修改同一数据,因此在读取数据时就立即加锁,防止其他事务修改该数据,直到当前事务完成。这种方式适用于写操作频繁、冲突概率高的场景。

与之相对的是乐观并发控制(Optimistic Concurrency Control),它不加锁,而是在提交时检查数据是否被他人修改过。EF Core 默认支持乐观并发,但通过原生 SQL 或事务隔离级别,我们也能实现悲观并发。

EF Core 中如何实现悲观并发控制?

EF Core 本身不直接提供“加锁”API,但我们可以通过以下方式实现悲观并发:

  • 使用 TransactionScopeDbContext.Database.BeginTransaction()
  • 设置合适的 事务隔离级别(如 SerializableRepeatableRead
  • 结合原生 SQL 使用数据库锁语句(如 SQL Server 的 WITH (UPDLOCK, ROWLOCK)

方法一:使用事务隔离级别

在 C# 中,我们可以使用 BeginTransaction 方法指定隔离级别:

using var context = new MyDbContext();using var transaction = await context.Database    .BeginTransactionAsync(System.Data.IsolationLevel.RepeatableRead);try{    // 查询并锁定记录    var product = await context.Products        .FirstOrDefaultAsync(p => p.Id == 1);    if (product != null)    {        product.Stock -= 1; // 扣减库存        await context.SaveChangesAsync();    }    await transaction.CommitAsync();}catch{    await transaction.RollbackAsync();    throw;}

这里使用了 RepeatableRead 隔离级别,它会阻止其他事务修改当前事务已读取的数据,从而实现一定程度的悲观锁效果。

方法二:使用原生 SQL 加锁(推荐用于高并发场景)

更精确的控制方式是直接在查询中加入数据库锁提示。以 SQL Server 为例:

var productId = 1;var product = await context.Products    .FromSqlRaw(@"SELECT * FROM Products WITH (UPDLOCK, ROWLOCK)                   WHERE Id = {0}", productId)    .FirstOrDefaultAsync();if (product != null){    product.Stock -= 1;    await context.SaveChangesAsync();}

其中:

  • UPDLOCK:表示获取更新锁,防止其他事务读取或修改该行
  • ROWLOCK:建议数据库使用行级锁而非表锁,提高并发性能
⚠️ 注意:使用原生 SQL 加锁依赖于具体数据库(如 SQL Server、PostgreSQL 等),不同数据库的锁语法不同,请根据实际使用的数据库调整语句。

常见事务隔离级别对比

隔离级别 脏读 不可重复读 幻读
ReadUncommitted ✅ 允许 ✅ 允许 ✅ 允许
ReadCommitted(默认) ❌ 禁止 ✅ 允许 ✅ 允许
RepeatableRead ❌ 禁止 ❌ 禁止 ✅ 允许
Serializable ❌ 禁止 ❌ 禁止 ❌ 禁止

对于悲观并发控制,通常选择 RepeatableReadSerializable。但要注意:Serializable 性能开销大,容易导致死锁,应谨慎使用。

总结

通过本文,你已经掌握了在 C# 和 EF Core 中实现 悲观并发控制 的核心方法。无论是通过设置 事务隔离级别,还是使用原生 SQL 加锁,都能有效防止并发冲突。记住,悲观锁适合写密集型场景,而乐观锁更适合读多写少的系统。

希望这篇教程能帮助你理解 Entity Framework Core 并发处理数据库锁机制 C# 的实际应用。动手实践一下吧!