首页 > 其他分享 >如何在EF Core中实现悲观锁

如何在EF Core中实现悲观锁

时间:2024-04-20 12:01:11浏览次数:28  
标签:Core await cartItem EF 悲观 SQL id

问题描述

在高流量场景下,绝对需要确保一次只有一个进程可以修改一块数据。假设你正在为一个极其受欢迎的音乐会构建售票系统。顾客们热切地抢购门票,最后几张票可能同时被售出。如果你不小心,多个顾客可能认为他们已经确保了最后的座位,导致超售!

Entity Framework Core是一个好工具,但它没有直接提供悲观锁的机制。其提供的乐观锁虽然也可以工作,但在高并发场景下,可能导致很多重试。

这里有一个简化的代码片段来说明面临的售票问题:

public async Task Handle(CreateOrderCommand request)
{
    await using DbTransaction transaction = await unitOfWork
        .BeginTransactionAsync();
    Customer customer = await customerRepository.GetAsync(request.CustomerId);
    Order order = Order.Create(customer);
    Cart cart = await cartService.GetAsync(customer.Id);
    foreach (CartItem cartItem in cart.Items)
    {
        // 哎呀...如果两个请求同时到达这里怎么办?
        TicketType ticketType = await ticketTypeRepository.GetAsync(cartItem.TicketTypeId);
        ticketType.UpdateQuantity(cartItem.Quantity);
        order.AddItem(ticketType, cartItem.Quantity, cartItem.Price);
    }
    orderRepository.Insert(order);
    await unitOfWork.SaveChangesAsync();
    await transaction.CommitAsync();
    await cartService.ClearAsync(customer.Id);
}

解决方案

上面虚构的示例用来演示这个问题。在结账期间,会验证每张票的剩余数量。如果此时多个并发请求尝试购买同一张票会怎样?最糟糕的情况是“超售”: 并发请求可能会看到有可售的门票,并完成结账。

要靠原生SQL来解决这个问题,EF Core调用原生SQL查询也很容易:

public async Task<TicketType> GetWithLockAsync(Guid id)
{
    return await context
        .TicketTypes
        .FromSql(
            $@"SELECT id, event_id, name, price, currency, quantity
            FROM ticketing.ticket_types
            WITH (UPDLOCK)
            WHERE id = {id}") // SQL Server: 锁定或立即失败
        .SingleAsync();
}

WITH (UPDLOCK):这是SQL Server中悲观锁的核心。它告诉数据库“锁定这一行,如果它已经被锁定,立即抛出一个错误。”

错误处理

我们将GetWithLockAsync调用包装在try-catch块中,以处理锁定失败,要么重试,要么通知用户。

结语

由于EF Core没有内置的方法添加查询提示,我们通过编写原始SQL查询。使用上述方法进行行级锁定。任何竞争的事务都将失败,直到当前事务释放锁定。这是一个简单的实现悲观锁的方法, 但在实际系统开发中很有用。

标签:Core,await,cartItem,EF,悲观,SQL,id
From: https://www.cnblogs.com/odyssey/p/18147541

相关文章

  • coredump时core文件生成
    要想生成core文件分两步:分配空间使用ulimit-a查看Linux资源分配情况,一般core后面的空间为0.可以使用ulimit-cunlimited设置为无限制大小,或使用ulimit-c100设置大小100Bytes修改路径默认路径很怪,一般需要修改到可执行文件的同一目录下,可以在sysctl.conf文件末尾添加一行......
  • Asp-Net-Core开发笔记:使用alpine镜像并加入健康检查
    前言使用docker部署AspNetCore应用已经是标配了,之前我一直使用mcr.microsoft.com/dotnet/aspnet:8.0这类镜像,简单粗暴,不过可以使用alpine进一步优化镜像大小。很多开源工具的docker都有健康检查,这次我顺便也给加上了。添加健康检查注册服务builder.Services.AddHea......
  • [题解]ABC209F Deforestation
    ABC209FDeforestation首先我们可以思考\(a_i\)和\(a_{i+1}\)先砍哪棵花费少。可以看出,当\(a[i]<a[i+1]\)时,先砍\(a[i+1]\),反之亦然。所以这个题转化成了:给定\(n-1\)个关系,分别表示\(n\)个值中相邻两个的大小关系,问满足这些关系的序列个数。与AtcoderEducationalDPContest......
  • Reflective Journal II
    AfterIwasaskedtodoavideopresentation,IdecidedwhoIwasgoingtointroduceandwhattocoverinmypresentationatfirst.ThenIbegantowritethetextinthePPT.Duringtheprocess,ImadeafewadjustmentstomakemyPPTmoreaesthetic.Fina......
  • Reflective Journal ∥
    1.First,Ichoseasuitabletheme,madetheopeningandclosingpages,thenconfirmedthedirectory,anddecidedthecontentofeachPPTpage,whichincludesimages,animations,andvarioustextformatsthatneedtobeset.Aftercompletingit,Irereadi......
  • IIS 执行此操作时出错。 详细信息:web.config 错误,.net core项目
    一、IIS执行此操作时出错。详细信息:web.config错误,.netcore项目   运行报错错误信息提示的很明确:IISWebCore模块问题二、解析:IIS下报错,但是直接启动exe文件可以正常运行。 三、解决方案先安装IIS,然后安装Asp.netCore运行时。 更多:IIS10隐藏https......
  • Effective Python:第8条 用zip函数同时遍历两个迭代器
    用Python内置的zip函数来实现。这个函数能把两个或更多的iterator封装成惰性生成器(lazygenerator)。每次循环时,它会分别从这些迭代器里获取各自的下一个元素,并把这些值放在一个元组里面。names=["Cecilia","Lise","Marie"]counts=[len(n)forninnames]max_count=......
  • Codeforces 1824C LuoTianyi and XOR-Tree
    考虑到肯定如果能在这个节点让子树的值尽量相同肯定更好,这样子不会与上面的操作相冲突。于是有个\(\text{DP}\)的思路。记\(f_{u,i}\)为\(u\)子树内叶子节点的值都变为\(i\)的最小代价。这个有一个很好的性质,就是\(\maxf_{u,i}-\minf_{u,i}=1\)。这是因为考......
  • Codeforces Round 932 (Div. 2)题解(c、d)
    CodeforcesRound932(Div.2)C.MessengerinMAC题目大意给定一些\(a_i\)\(和b_i\),选出尽量多的\(a_i和b_i\),使得\(\sum_{i=1}^ka_{p_i}+\sum_{i=1}^{k-1}\left|b_{p_i}-b_{p_{i+1}}\right|\)小于给定的\(l\)。题目解析由于题目没有要求\(\{p\}\)是升序排列的序列,因此......
  • 《Pyramid Codes: Flexible Schemes to Trade Space for Access Efficiency in Reliab
    问题1:Introduction部分,第五段,[16,12]ERC和3-Copy达到了相同的可靠性,在每一个块独立失败概率为0.01的情况下,这个是怎么证明的。问题2:同上,第五段后半部分,那么多的IO次数是怎么计算出来的。在系统中,要分清各种性能指标,读和写是不一样的,第六段提到的是写性能,主要方法就是先用复制的方......