我有一個購物車,我建立了自己的使用會話變量來維護請求狀態的購物車。我有一個增量和減量按鈕,允許用戶增加或減少購物車中產品的數量。這通過Ajax請求發生。購物車類通過在構建時將購物車恢復出會話並在銷燬時將購物車保存回會話中來操作。與php會話和ajax請求的競爭條件
<?php
class Cart {
/**
* constructor
*/
public function __construct(){
//restore cart
$this->restore();
}
/**
* destructor
*/
public function __destruct(){
//save cart
$this->save();
}
/**
* restore
*/
public function restore(){
//retrieve session info
if(Session::has('cart')){
//get cart
$session = Session::get('cart');
//assign session info
$this->data = ($session['data']);
$this->rates = $session['rates'];
$this->lines = $session['lines'];
}
}
/**
* save
*/
public function save(){
Session::put('cart', $this->forSession());
}
我遇到的問題是具有多個Ajax請求的競爭條件。用戶可以多次點擊該按鈕,發送多個Ajax請求。因此每個請求都會拉動會話的當前狀態,執行操作,然後保存它。問題是以前的交易不一定完成並保存時,它的購物車。我的第一個修正是讓任何後續的Ajax請求取消前一個請求,既減少不必要的(立即覆蓋)請求,也幫助避免這種競爭條件。雖然它似乎有所幫助,但它仍然古怪。所以我的下一個想法就是在源頭上攻擊它,即購物車類本身。我的想法是實施某種類型的「鎖定」,以防止在前一個操作完成之前訪問購物車。這個想法看起來像這樣。
<?php
/**
* is cart locked
*/
public function isCartLocked(){
if(Session::get('cartLock') === 1){
sleep(1);
$this->isCartLocked();
}
}
public function restore(){
Session::put('cartLock', 0);
//check if cart is locked
$this->isCartLocked();
//lock cart
Session::put('cartLock', 1);
...
}
public function save(){
//unlock the cart
Session::put('cartLock', 0);
...
}
現在第一個問題是,我應該做這樣的事情,鎖定?然後,如果是這樣,這是一個體面的方式來處理它?
在我第一次嘗試它之後,我似乎遇到的問題是析構函數不一定總是被調用,這導致我的購物車保持鎖定狀態,並最終導致超時錯誤。
感謝您的幫助!
debouncing看起來像是一個很好的解決這個問題。雖然這是我將考慮實現的東西,但我也更喜歡服務器端解決方案,所以我從源頭解決問題,並且不要依賴客戶端解決方案來防止發生這種情況。 – 2015-03-13 19:26:28