Php 如果条件为true,则安全MYSQL插入多行

Php 如果条件为true,则安全MYSQL插入多行,php,mysql,database,laravel,transactions,Php,Mysql,Database,Laravel,Transactions,我正在做一个小项目,我的票是有限的,用户可以购买多种数量和不同类型的票。我需要确保只有在购买的票证不超过每种类型的可用票证的情况下,才会插入交易 这样做安全吗 $selectAvailableTickets = getTicketAvailability(1,2,3) //Assume that this returns rows of event_id, tickets_available foreach($selectAvailableTickets as $availableEventT

我正在做一个小项目,我的票是有限的,用户可以购买多种数量和不同类型的票。我需要确保只有在购买的票证不超过每种类型的可用票证的情况下,才会插入交易

这样做安全吗

$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
这样做是否足以确保只有在购买不超过该特定类型票证的可用票证的情况下才能进行交易


我在想,如果有多个用户几乎同时进行交易,允许一个用户插入的条件可能为假,即使返回为真,如果另一个人购买了票证,却没有给另一个人留下任何票证,而另一个人也进行了交易,并且恰好进行了比另一个人更快的交易。

为了保护您的数据库不受这些不必要的故障的影响,选择并插入了信息不匹配您可以请求事务锁。这是一个非常有趣的话题,值得一读!对于您的实现,您需要知道的是,您可以请求锁,并且只有在所有查询都成功时才能执行查询

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;
});
DB::事务(函数(){
//获取可用票数
$event=event::where('event_id',$event_id)->lockForUpdate()->get();
$available\u tickets=$event->available;
如果($available_tickets<$tickets_to_purchase){
//已售出的票证,抛出回滚事务异常
抛出新异常();
返回
}
//安全地创建票据,因为我们是唯一拥有锁的人
$ticket=新票()
$ticket->counters\u of theu tickets=$tickets\u to\u purchase;
$ticket->save();
$event->available=$available\u tickets-$tickets\u to\u purchase;
$event->save;
});
这里我们使用的是一个,这个锁意味着除了获得锁的person/php实例之外,没有人可以读取这个事件的可用票证数量,直到锁被释放。由于我们在同一交易中创建了票证并更新了可用票证,我们可以确保我们是唯一能够购买上述票证的人


当然,函数中的所有代码都可以扩展以获取所有相关信息(使用适当的锁)。在这里,您还可以使用for循环获取所有票证类型的相关信息。

您要查找的是,以及@milo526,谢谢您的建议。我想我明白了。但我是否在事务之外实现该条件?比如,在我实施插入之前检查条件?非常感谢您的好意,先生。现在我还有最后一个问题。锁定是否会带来任何可能的风险。。网络超时?我的意思是,如果有人有锁,进程可能会变慢,因为进程是排队的,如果队列中有这么多呢?无论如何,如果他们的请求等待时间太长,而这在低用户数的情况下是不可能发生的,那么它的安全性比超时要好。是的,这确实会降低其他用户的应用程序速度,但正如您已经说过的,这是必要的。这就是为什么你应该只在真正需要的时候使用事务,并在事务中执行尽可能少的代码。我更希望它安全,我会一直这样做,直到我找到一个性能损失更少的更好的解决方案,但这可能不会在不久的将来发生,因为我还有很多东西要学习。非常感谢你!