-1

我正在建立一个酒店式的预订系统,但我迷路了。我在添加预订的确切预订时刻卡住了,我担心即将到来的情况。

我的流程非常简单,它允许多个用户完成同一个房间的预订过程,直到其中一个用户先于其他用户按下预订按钮。预订信息保留在会话中,并且在有人到达最后一步并按“预订”之前永远不会存储在数据库中。在每一步中,系统都会检查房间是否可用,如果不可用,则会给出错误页面。

现在的问题是防止竞争条件与最后一个强制检查是否仍有足够的房间相结合:

当用户在最后一步时,他/她选择付款方式并按下预订按钮。在检查所选付款选项是否正常(表单数据未更改)后,它会重定向到预订控制器,其中:

预订控制器

<?php
ReservationController extends JControllerLegacy{

public function placeReservation(){

    //Do some checks to prevent direct access, booking existence and user completed all steps

    $reservatioModel = $this ->getModel('Reservation')
    if(!$reservationModel->placeReservation()){
         //set errors and redirect to error page
         return false;
    }

    //booking had been placed, passes the data to payment plugin
}

?>

预订型号:

 <?php
 ReservationModel extends JModelLegacy{

public function placeReservation(){

    //Get all variables and objects

    //Lock the tables to prevent any insert while the last check
    $db ->lockTable(#__bookings);
    $db ->lockTable(#__booking_room);

    //Perform the last mandatory check with tables locked to prevent read the table right one moment before another transaction insert the booking and allowing overbooking. THIS CHECK MUST BE 100% SURE NO ONE ELSE IS MANIPULATING/READING THE TABLE
    if(!$this ->checkRoomsAvailability($data))
        return false;

    try{
        $db ->transactionStart();

        //Add the reservation in the booking table
        if(!$this ->_saveBooking()){
           $db ->rollBack();
           return false;
        }

        //Add the room/s to the middle table #__booking_room
        if(!$this -> _saveRooms())
           $db ->rollBack();
           return false;
        }

        $db ->transactionCommit();

    }catch(Exception $e){

        $db ->rollBack();
        $this ->setError('We were not able to complete your reservation.');
        return false;
    }

    $db ->unlockTables();

}
 ?>

上面提到的表是 InnoDB,#__bookings 保存预订,#__booking_room 保存所选房间的信息(如 avg_price、房间数等),它有一个外键到 #__rooms 和一个到 #__bookings

我在担心什么?

1 - 我在最后一次可用性检查期间使用了其他表,而不是两个锁定的表,并且给了我错误。

2 - 当第二个用户的执行到达表锁定点时,它是等到他们获得空闲还是引发错误/异常?我可以捕获异常并将用户重定向到错误页面,但小盒表并不意味着已放置预订,在保存信息时可能会出现任何问题。

我希望我的工作流程没问题,请让我知道我是否可以继续,或者我应该改进我的代码。

谢谢

编辑:

值得一提的是,商业理念就像 Expedia、预订等,您可以在每次预订时选择更多的房间类型和单位。事实上,我的房间桌子不是针对特定/真实房间的,而是针对房间类型,如果尚未预订,则每天都有固定数量的可用单元。

4

2 回答 2

1

我的方法会更简单。在存储实际预订的表中,我将有一个用于预订特定房间的外键,并有一个UNIQUE字段索引roomID, date。这将确保相同的 roomID 不会在同一日期被记录两次。

接下来,当客户确认预订时,我会像您当前所做的那样运行事务中的所有内容。当代码到达最后一个位置并尝试插入新的预订时,如果在另一位客户预订该房间之前的片刻,DB 将不允许您在该日期为该房间插入另一个预订。那时我会:

  • 回滚并抛出错误,或者
  • roomID如果还有另一个相同类型的房间仍然可用,请在另一个房间(有自己的房间)再试一次
于 2017-08-13T18:22:49.657 回答
0

我不能说您的工作流程(即业务领域)是否是正确的选择,因为这取决于您的业务。但从技术上讲,您希望进行预订交易,该交易还提供针对双重预订的检查。最简单的方法可能是一个房间预订日期表,对房间是和日期有唯一约束。因此,在您的预订交易期间,您还可以将带有房间 ID 的每一天插入到表中,并且唯一约束将确保第二次尝试将失败。

PS:如果一个表被锁定,PHP 将等待解锁。不会抛出异常(至少如果 x 秒后连接没有关闭)

于 2017-08-13T18:30:43.900 回答