EF Core 如何处理多个预订请求并发的理想方式

EF Core ideal way on how to handle concurrency for multiple reservation requests

概览

嗨,我正在开发一个使用 ASP.NET Core 作为后端和 Vue.js 的小应用程序作为前端。作为数据库访问,我为 SQL Server 选择了 Entity Framework Core。我的疑问是处理这种情况的理想方式:给定来自多个客户的同时2个或更多请求如何使办公室座位预订仅针对一个请求成功。


数据库结构

上下文如下:


我的疑惑

给定一个可用座位,如果同时处理两个在同一日期预订办公室座位的请求,并且都读取有预订空间,他们将在 Reservations table 即使理论上只有一个空间

以下是我一直在考虑的几个解决方案:

对于第二个选项,当一个请求成功插入预订时,后续请求的读数将考虑它,如果没有更多的位置,则不会执行插入。另一方面,如果更多的请求同时读取相同的数据,它们将执行插入,但在第二次读取时它们将能够检查是否违反约束并删除 Reservations 中的行。在最后一个场景中,可用座位尚未分配给任何请求,但至少遵守办公室最大座位数的限制。


那么我的问题是什么?

我的问题是是否有设计模式或最佳实践来解决上述问题。

数据库事务是您的朋友。但是,ReadCommitted 的默认交易 isolation level 将无法满足您的需要。不保证您查询的数据——是否有预订房间——在您的工作完成之前不会改变;它只保证您收到的数据来自已提交的交易。通过使用 Serializable 隔离级别,您可以保证在处理事务的进程完成其工作(检查可用性然后添加预订)之前不会添加竞争预订。

This documentation 包含如何在 Entity Framework 上下文中使用事务的示例。这段代码应该给你大致的想法:

// start a transaction with the higher isolation level
using (var dbContextTransaction = context.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
    try
    {
        // run your query to ensure no competing reservation exists
        // use AsNoTracking to ensure the query runs against your database in the transaction context
        context.Reservations.AsNoTracking()...;

        // if it is valid, insert your reservations
        context.Reservations.Add(...);

        // run the insert statement
        context.SaveChanges();

        // commit the transaction
        dbContextTransaction.Commit();
    }
    catch
    {
        // roll back the transaction if anything went wrong so that your database isn't locked
        dbContextTransaction.Rollback();

        throw;
    }
}