2017-08-13 106 views
-1

我正在建立一個酒店式預訂系統,我正在放鬆方式。我在預訂時刻卡住了什麼時候添加預訂,我擔心來臨的情況。預防酒店預訂系統中的競爭條件和鎖定表PHP/MySQL

我的流程非常簡單,它允許多個用戶通過同一個房間的預定過程,直到其中一個人按下預定按鈕之前的其他人。預訂信息保存在會話中,直到有人到達最後一步並按「書」,永遠不會存儲在數據庫中。在每個步驟中,系統檢查房間是否可用,如果沒有,則提供錯誤頁面。現在

問題是防止競爭條件相結合,最後一個強制性的檢查,如果仍然有足夠的房間了:

當用戶在最後一步時,他/她選擇的付款方式,按書按鈕。檢查是否選擇的付款方式是確定的(表格數據沒有被修改)後,它重定向到保留控制器,其中:

預約控制器

<?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_p大米,房間數量等),它有一個外鍵和#__房間和一個#__預訂

我關心什麼?

1 - 我在最後的可用性檢查過程中使用其他表,而不是兩個鎖定,並給我錯誤。

2 - 當第二個用戶的執行到達表鎖定點時,它是否等到它們獲得空閒或是否會引發錯誤/異常?我可以捕獲異常並將用戶重定向到錯誤頁面,但是加密表表示並不意味着保留位置,保存信息時可能會發生任何問題。

我希望我的工作流程正常,請告訴我,如果我很好,或者我應該改進我的代碼。

感謝

編輯:

要被提及的經營思路是像Expedia的,即,預訂,等在那裏你被允許每個預訂選擇更多的房間類型和單位。事實上,我的房間的桌子不是針對特定/真實的房間,而是爲了房間類型,如果沒有預訂,每天都有固定數量的房間。

回答

0

我的方法會更簡單。在存儲實際預訂的表格中,我將爲預留的特定房間設置外鍵,併爲roomID, date的字段指定UNIQUE索引。這將確保同一個房間ID在同一日期不能被記錄兩次。

接下來,當客戶確認預訂時,我會按照您當前的操作在交易中運行所有內容。當代碼到達最後的位置並嘗試插入新的預訂時,如果在另一位客戶預留該房間之前的某個時刻,數據庫將不允許您在該日期爲該房間插入另一個預訂。這時候,我要麼:

  • 回滾和拋出的錯誤,或
  • 與另一間再試一次(有自己的roomID)如果仍然可用相同類型的另一個房間
+0

如果每個房間在#__房間表中有一排並且每個預訂的房間都有預訂,我可以接受您的答案,但是,你知道,那不是一個好選擇。我想讓用戶預訂多個房間是相同的預訂,即使因爲我管理的房間類型不僅僅是特定房間的單位數量。 –

+0

@MarcoC如果用戶預訂了多個房間,那麼請讓每個房間預訂其自己的記錄。它將在一個單獨的表中(不是'預訂'),並且所有這些記錄都有相同的'reservationID' - 一個外鍵。在這種情況下,'UNIQUE'索引仍然是'roomID,date'。由於你有其他的住宿(例如公寓),可能'roomID'不是最好的字段名稱,但是概念是相同的:對於特定空間被保留的唯一標識符 – BeetleJuice

+0

'保留特定空間的唯一標識符' - 最短但最準確的答案 –

0

我不能說你的工作流aka業務領域是否是正確的選擇,因爲它取決於你的業務。但從技術上講,你想要有一個預訂交易,也提供了一個雙重預訂的支票。最簡單的方法可能是一個房間預訂日期表,房間和日期有獨特的限制。因此,在您的預訂交易中,您還需要將每天的房間號插入表格中,唯一的約束將確保第二次嘗試失敗。

PS:如果一個表被鎖定,PHP將會等待解鎖。不會拋出任何異常(至少如果連接在x秒後不關閉)

+0

嗨@尼爾斯,謝謝你的回答。我編輯了指定業務類型的帖子,並補充說,房間選擇是每種類型,因爲我也租用單位,所以不同數量的單位和類型(特大號牀,兩張單人牀等) –

+0

仍然是同樣的答案。您必須確保數據永遠不會處於「不可能」狀態。約束和交易是你的朋友。如果你只是鎖定表格,你會確保預訂會一個接一個地發生,但這不會阻止你插入重複的數據。 –