导读:本期聚焦于小伙伴创作的《什么是并发冲突?在C#中如何处理数据库并发问题?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《什么是并发冲突?在C#中如何处理数据库并发问题?》有用,将其分享出去将是对创作者最好的鼓励。

并发冲突指的是多个操作在同一时间段内同时访问并修改同一份数据资源,最终导致数据状态不符合预期的问题。在数据库操作中,这类问题会直接影响业务数据的准确性,是后端开发中需要重点处理的技术点。

什么是并发冲突?在C#中如何处理数据库并发问题?

并发冲突的产生场景

最常见的并发冲突场景是两个用户同时查询并修改同一条数据:

  • 用户A和用户B同时查询到某商品的库存为10
  • 用户A提交订单,将库存减1,此时数据库库存变为9
  • 用户B也提交订单,基于自己查询到的10库存减1,将库存更新为9
  • 最终库存实际应该是8,但是被错误更新为9,产生了数据不一致

C#中处理数据库并发的两种核心方案

1. 悲观锁方案

悲观锁的核心思路是假设并发冲突一定会发生,在操作数据前先对数据加锁,其他操作需要等待锁释放才能访问该数据。在C#中使用EF Core时,可以通过DbContext的事务结合数据库的锁机制实现悲观锁。

以下是使用SQL Server的悲观锁实现示例:

using (var context = new AppDbContext())
{
    using (var transaction = context.Database.BeginTransaction())
    {
        // 查询数据时加排他锁,其他事务无法修改该数据
        var product = context.Products
            .FromSqlRaw("SELECT * FROM Products WITH (XLOCK, ROWLOCK) WHERE Id = {0}", 1)
            .FirstOrDefault();
        
        if (product != null && product.Stock > 0)
        {
            product.Stock -= 1;
            context.SaveChanges();
        }
        
        transaction.Commit();
    }
}

悲观锁的优点是能够完全避免并发冲突,缺点是会阻塞其他操作,高并发场景下性能较差,适合并发量不高、数据一致性要求极高的场景。

2. 乐观锁方案

乐观锁假设并发冲突不会频繁发生,不在操作前加锁,而是在更新数据时判断数据是否被其他操作修改过。EF Core原生支持乐观锁,最常用的实现方式是给数据表添加RowVersion时间戳字段。

首先定义包含RowVersion的实体类:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Stock { get; set; }
    // 时间戳字段,EF Core会自动维护该字段的值
    public byte[] RowVersion { get; set; }
}

然后在DbContext中配置该字段为并发令牌:

public class AppDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property(p => p.RowVersion)
            .IsRowVersion(); // 标记为并发令牌
    }
}

执行更新操作时,EF Core会自动在更新语句中加入RowVersion的判断,如果数据被其他操作修改过,就会抛出DbUpdateConcurrencyException异常,我们可以在异常中处理冲突逻辑:

using (var context = new AppDbContext())
{
    var product = context.Products.Find(1);
    if (product == null) return;
    
    try
    {
        product.Stock -= 1;
        context.SaveChanges(); // 如果RowVersion不匹配,这里会抛出异常
    }
    catch (DbUpdateConcurrencyException ex)
    {
        // 处理并发冲突:可以重新查询最新数据重试,或者提示用户数据已被修改
        var entry = ex.Entries.Single();
        var databaseValues = entry.GetDatabaseValues();
        if (databaseValues != null)
        {
            // 获取数据库中的最新库存
            var latestStock = (int)databaseValues["Stock"];
            if (latestStock > 0)
            {
                // 基于最新数据重试更新
                entry.CurrentValues.SetValues(databaseValues);
                ((Product)entry.Entity).Stock -= 1;
                context.SaveChanges();
            }
        }
    }
}

乐观锁的优点是性能较好,不会阻塞其他操作,缺点是冲突发生时需要处理重试逻辑,适合高并发、冲突概率较低的场景。

两种方案的选型建议

对比维度悲观锁乐观锁
并发性能低,会阻塞其他操作高,无阻塞
实现复杂度较低,依赖数据库锁机制中等,需要处理冲突异常
适用场景并发量低、数据一致性要求极高高并发、冲突概率低

在实际C#开发中,大部分业务场景优先选择乐观锁方案,只有在数据一致性要求极高且并发量很小的场景下才考虑使用悲观锁。同时需要注意,无论使用哪种方案,都要做好异常处理,避免并发冲突导致业务功能异常。

并发冲突数据库并发C#乐观锁悲观锁修改时间:2026-06-23 19:45:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。