我正在做一个小项目,我的门票数量有限,用户可以购买多种数量和不同类型的门票。我需要确保只有在要购买的门票不超过每种类型的剩余门票时才会插入交易。
这样做是否足够安全?
$selectAvailableTickets = getTicketAvailability(1,2,3) //Assume that this returns rows of event_id, tickets_available
foreach($selectAvailableTickets as $availableEventTicket){
foreach($ticketsToPurchase as $purchase){
if($purchase->event_id == $availableEventTicket->event_id){
if($purchase->ticket_count > $availableEventTicket){
$hasExceedingPurchase = true;
}
}
}
}
if($hasExceedingPurchase) //Cancel transaction, otherwise, insert and proceed
这样的事情是否足以确保只有在购买不超过特定类型票证的可用票证时才会进行交易?
我在想,如果有多个用户几乎同时进行交易,那么允许一个用户插入的条件可能是假的,即使如果另一个人购买门票则返回为真,而对于另一个人则不会也做了一笔交易,恰好比另一笔交易更快。
答案 0 :(得分:2)
为了保护您的数据库免受选定和插入的信息不匹配的这些意外故障,您可以请求事务锁定。这是一个非常有趣的话题,值得一读!对于您的实现,您需要知道的是,如果所有查询都成功,您可以请求锁定并仅执行查询。
DB::transaction(function() {
//get available ticket count
$event = Event::where('event_id', $event_id)->lockForUpdate()->get();
$available_tickets = $event->available;
if($available_tickets < $tickets_to_purchase){
//tickets where already sold, throw exception to rollback transaction
throw new Exception();
return
}
//safely create tickets since we are the only one with the lock
$ticket = new Ticket()
$ticket->amount_of_tickets = $tickets_to_purchase;
$ticket->save();
$event->available = $available_tickets - $tickets_to_purchase;
$event->save;
});
这里我们使用pessimistic lock,这个锁意味着没有人可以读取此事件可用的票数,除了获取锁之前的人/ php实例,直到锁被释放。由于我们在同一笔交易中创建门票并更新可用门票,因此我们可以确信我们是唯一能够购买门票的人。
当然,函数内的所有代码都可以扩展为获取所有相关信息(使用适当的锁)。在这里,您还可以使用for循环来获取所有故障单类型的相关信息。