如何使用C#和SQL服务器实现保证不重复的股票发行系统

How to implement a stock issuance system ensuring no duplication using C# and SQL Server

我有一个用 C# API .Net Core 6 实现的系统。数据库是 SQL 服务器,我正在使用 Entity Framework。我有 table 个单独的库存项目(每个项目都有自己的记录)。当我出售一件商品时,我通过将 'Sold' 字段的值从 NULL 更改为 DateTime.UtcNow 来记录其销售日期。当我需要出售一件商品时,我想获得对我库存 table 中该类别商品之一的参考,我用 ctx.Stock.Where(t=> t.Sold == null && t.Category==cat).First() 如果 return 存在的话,它是我的一个项目。然后该项目的 'Sold' 字段已更新。

由于系统是通过 API 访问的,因此代码可能会同时被调用两次(或更多次),两次调用都会 return 来自ctx.Stock.Where(t=> t.Sold == null && t.Category==cat).First() ,然后两者都会将其标记为已售出,并且在为它们调用 SaveChanges 时,它会保存后面的 'Sold' 值,并且只有 1 个股票记录会被记录为已售出,而实际上已经发生了 2 个销售。

现在,如果在发生此类情况时触发 DbUpdateConcurrencyException,则可以避免这种情况。有谁知道是否会这样?在那种情况下,我想可以使用 ctx.Stock.Where(t=> t.Sold == null && t.Category==cat).First( ) 。这是最好的方法吗?

否则会有一个单例服务,它在 ctx.Stock.Where(t=> t.Sold == null && t.Category==cat) 的 运行 周围有锁。填充的 'Sold' 字段的 First() 和 SaveChanges 是更好的选择吗?这可以确保没有可能的 DbUpdateConcurrencyException,因为它是顺序的,但是锁可能会成为问题。

我不太喜欢信任数据库。如果您希望能够水平扩展您的应用程序并能够访问 Redis 缓存,您可以使用 RedLock 来防止两个调用同时访问数据库。否则只需使用一个简单的锁。该服务不必是单例...您只需要使用静态对象进行锁定。