我有一个购物车,我建立了自己的使用会话变量来维护请求状态的购物车。我有一个增量和减量按钮,允许用户增加或减少购物车中产品的数量。这通过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