电影院座位预订系统如何防止多个用户预订相同的座位?


34

在电影院里,我去那里有售票亭,您可以选择想要的座位。他们也有一个相同的网站(该网站还有一个倒计时计时器,例如30秒,您必须在其中选择座位)。

虽然我了解诸如数据库事务之类的知识以及处理多个同时用户的其他技术,但我还是无法理解如何允许多个人同时选择一个席位;是否像第一个按“购买”的人那样简单,然后另一个人将收到错误消息,还是我错过了什么?


10
“是不是像第一个按下BUY的按钮那样简单,然后另一个人就会收到错误消息”。那。
yannis 2011年

2
是的,可能在忙碌的一天里,有十几台机器,这似乎很痛苦。
mbwasi 2011年

2
也许吧,但是请记住,用户将把大部分时间都花在其他屏幕上(输入付款明细,等待票据打印等),因此他们不会同时选择座位,而不是每个人都有相同的席位偏好,因此即使是在同一时间进行选择的人也可能会选择不同的席位。我不希望有那么多冲突。
Dave Sherohman 2011年

2
@吉姆 对于每种可能的解决方案,如果两个客户都在同一时间(以毫秒为单位)按购买,则一个将得到服务,而另一个将收到某种错误消息。有很多方法可以最大程度地减少发生这种情况的可能性(技术和概念上都如答案中所述),但是在特殊情况下,确实会发生这种情况,然后一个请求将得到处理,而另一个请求将失败。就如此容易。
yannis 2011年

3
@吉姆 这不是一种行为。并发工作到一定程度,如果两个请求都恰好在同一时间到达,那么一个请求将失败。当然,您可以围绕这一问题构建一个不错的错误消息,如Hand-E-Food的评论中所述,但事实仍然存在:这就像处理一个请求而使另一个请求失败一样简单。我并不是说您不应该做所有事情来确保失败尽可能地易于用户使用,或者您不应该对此进行保护。
yannis 2011年

Answers:


27

执行此操作的经典方法是使用事务数据库(因此不会发生冲突),并临时分配给您一个席位,该席位会在一定时间(例如信息亭的10分钟)后失效,从而给您足够的时间工资。如果(客户可见的)交易失败或超时,则可以将席位分配释放回池中。(所有状态更改都通过事务数据库进行处理,并且一个客户可见的事务可能需要许多数据库级事务。)

航空公司将使用类似的系统(尽管由于需要处理多个航程,所以会更加复杂!)在线预订座位。我想超时会更长一些;机票通常比电影票预订得更早,而且价格也更高。


请注意,我当地的电影院实际上并不正常分配座位。取而代之的是,他们为座位预留了过多的空间,这样人们就可以大惊小怪地出现。这是一种不同的技术,但与您的问题无关!
Donal Fellows,

类似于为体育赛事挑选座位。您可以决定是否保留3分钟的N个席位,然后再决定是否实际需要并完成付款。
AndyMcKenna

请注意,有两个不同的过程,例如,购买飞机座位:首先,您在未分配座位的情况下购买机票。其次,当您获得登机证时(或者如果您在线办理登机手续),那么您将获得席位。机票数量实际上已经超卖了,因为他们知道平均而言,航班不会出现一定数量的机票。但是,席位分配似乎可以通过在签到时随机分配一个席位(先到先得)来工作,然后允许您通过选择一个可用席位来更改席位,然后在一次交易中完成转账。
Scott Whitlock

2
@DonalFellows您能解释一下暂定分配部分吗?您是要在一段时间内为用户保留一些席位吗?我仍然试图摆脱这种系统所面临的挑战。
Sandeepan Nath

1
@SandeepanNath注释中不正确,但原理很简单。将座位置于“临时分配”状态,并同时记录该状态的超时。如果预订完成,座位将被完全分配。如果没有达到超时,则(最终)将座位移回主池。(此外,如果用户明确取消,则将座位直接移回游泳池。无需等待。)
Donal Fellows

4

如今,您所看到的30秒通常更像是15分钟。我认为在此期间没有活动的数据库事务。

如果我要设计这样的系统,那么我将这样做:拥有业务对象BookingReservation。预订基本上是确认(即付费)的预订。我会将它们存储在同一数据库表中,并按一个或两个属性进行区分。

在获取可用座位时,您将同时查询预订和预订。

当有人选择座位时,您将创建一个新的预订,从而向其他顾客显示该座位。同一席位的第二次预订将被拒绝-数据库更新或插入将失败。如果客户确认/支付了预订,则将其转换为预订。在定期批处理作业中,您删除所有15分钟(或您给客户的时间)之前的预订。



1

这里至少涉及两个业务流程。

  • 流程一:

显示可用的座位。

  • 流程二:

预订选定的座位。

由于这些过程不会彼此紧随,并且由于两个人可以选择同一席位,因此出现了并发问题。

如果您的数据库设计分配了正确的唯一性约束,那么以下各项的组合:

-剧院ID

-SeatID

-EventID

是唯一的,那么数据库将防止重复。

以下情况也是可能的,但上述建议的实现将解决以下情况:

假设可以显示给定剧院和给定事件可用的网格视图:

  1. User1显示可用座位(并获得座位1和2)
  2. User2显示可用座位(并获得座位1和2)
  3. User1通过电话与客户交谈
  4. User2去为其客户预订座位2
  5. User1尝试为其客户预订座位2(因为它在屏幕上显示为可用)
  6. 唯一索引可防止步骤5交换数据。

因此,您所需要做的只是正确的数据库设计和对约束的正确选择。

如果需要,可以使用事务队列来使用其他更复杂的方法。在这种情况下,请求首先被写入队列,然后每n秒触发一个进程,但这在您的情况下几乎没有必要或不实际。

真正有趣的部分是用户1的列表网格应显示什么?


1

如果延迟分配特定席位,则可以避免出现竞争情况。

  1. 收集客户的座位偏好(座位数量,价格,剧院面积,相邻座位强制等)。
  2. 将请求的座位偏好设置保存在队列中
  3. 从队列中拉出一对一的座位请求,根据喜好分配座位,并在找到座位后完成预订。
  4. 如果预订完成,通知客户并邮寄机票;否则,通知客户没有任何符合偏好的票证。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.