C# core 乐观并发控制

Entity Framework (EF) 本身并不提供专门的"金额锁"操作,因为这通常是业务逻辑的一部分,而不是数据访问层面的功能。不过,如果你想确保对数据库中的金额字段进行安全的更新,以避免并发问题,可以使用乐观并发控制或悲观锁定策略。

乐观并发控制

乐观并发控制假设多个事务更新同一记录的冲突概率较低。它允许多个进程同时读取一个记录,并在提交更新时检查记录是否自上次读取以来被修改过。如果记录已被修改,则更新会失败。在Entity Framework中,这通常是通过在模型中使用ConcurrencyToken来实现的。

例如,在模型定义中,你可以指定一个属性作为并发令牌:

csharp 复制代码
csharp复制
public class Account
{
    public int AccountId { get; set; }
    [ConcurrencyCheck]
    public decimal Balance { get; set; }
    // 其他属性...
}

或者在OnModelCreating中使用Fluent API配置:

scss 复制代码
csharp复制
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Account>()
        .Property(a => a.Balance)
        .IsConcurrencyToken();
}

这样,在更新操作中,EF Core会检查在读取记录后该记录是否被修改过。如果在更新时检测到并发冲突(即记录已被其他事务修改),EF Core会抛出一个DbUpdateConcurrencyException异常。

悲观并发控制

悲观并发控制假设冲突很可能会发生,并且它通过在事务开始时锁定记录来防止冲突。在EF Core中,你可以通过使用事务并显式指定锁定行为来实现悲观锁定,例如使用SELECT ... FOR UPDATE语句。

在EF Core中执行悲观锁定的一个例子:

csharp 复制代码
csharp复制
using (var context = new YourDbContext())
{
    using (var transaction = context.Database.BeginTransaction())
    {
        try
        {
            // 查询要更新的账户,并锁定该记录
            var account = context.Accounts
                .FromSqlRaw("SELECT * FROM Accounts WHERE AccountId = {0} FOR UPDATE", accountId)
                .SingleOrDefault();

            if (account != null)
            {
                // 执行金额更新操作
                account.Balance += amount;  

                context.SaveChanges();
                transaction.Commit();
            }
        }
        catch (Exception)
        {
            transaction.Rollback();
            // 处理异常
        }
    }
}

请注意,不是所有的数据库系统都支持SELECT ... FOR UPDATE(这是SQL悲观锁的一种实现),并且确切的SQL语法可能因数据库类型而异。上面的代码适用于支持此类查询的数据库(如PostgreSQL,MySQL等)。对于SQL Server,你可能会使用不同的锁定语句,例如WITH (UPDLOCK, ROWLOCK)

注意: 使用悲观锁定策略时,要特别注意死锁的可能性以及对性能的影响。

在进行金额更新等重要业务操作时,要确保你的代码可以正确处理并发场景,确保数据的一致性和完整性。如果需要,也应该在事务中执行这些操作,以确保操作的原子性。

相关推荐
宝桥南山2 天前
Blazor Web Assembly - 体验一下Authentication State从Server共享给Client
microsoft·微软·c#·asp.net·.net·.netcore
rockey6272 天前
C#脚本引擎之AScript与DynamicExpresso对比
c#·.net·script·动态脚本
qq_548612453 天前
.NET 平台报表工具汇总(.NET Framework /.NET6-8,中国式复杂报表、Web 嵌入、填报、导出打印)
前端·.net
公子小六3 天前
基于.NET的Windows窗体编程之WinForms音频控件
windows·microsoft·c#·.net·音视频·winforms
界面开发小八哥3 天前
界面控件DevExpress Blazor v26.1新版亮点 - Navigation(导航)
javascript·.net·界面控件·blazor·devexpress·ui开发
用户298698530143 天前
C# 实现 PowerPoint 多格式转换:图片、PDF 与 SVG 实战
c#·.net·svg
李高钢3 天前
【WPF】从 Avalon 到 .NET 10:WPF 平台演进史与特性全览
.net·wpf
刚子编程4 天前
用 Inno Setup 把 .NET 程序打包成安装包:从零到发布的完整指南
.net·inno setup·码农刚子·.net 程序打包·安装脚本编写
界面开发小八哥4 天前
界面控件DevExpress Blazor v26.1新版亮点 - TreeList & 数据编辑器
javascript·编辑器·.net·界面控件·blazor·devexpress·用户界面
rockey6275 天前
C#脚本引擎之AScript与Flee对比
c#·.net·script·eval·动态脚本