与php会话和ajax请求的竞争条件

时间:2015-03-13 19:12:13

标签: php jquery ajax session-variables laravel-5

我有一个自己构建的购物车,它使用会话变量来维护请求中的购物车状态。我有一个递增和递减按钮,允许用户增加或减少购物车中的产品数量。这是通过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请求。因此,每个请求都会拉出会话的当前状态,执行操作,然后保存它。问题是以前的交易未必在restore购物车时完成并保存。我的第一个修复是让任何后续的Ajax请求取消前一个请求,以减少不必要的(立即覆盖的)请求,并帮助避免这种竞争条件。虽然它似乎有所帮助,但它仍然是古怪的。所以我的下一个想法是在源头攻击它,即购物车类本身。我的想法是实现某种类型的锁定&#39;防止在前一次操作完成之前访问购物车。这个想法看起来像这样。

<?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);

    ...
}

现在第一个问题是,我应该做这样的事情,锁定?然后,如果是这样,这是一个处理它的好方法吗?

在我第一次尝试之后,我似乎遇到的问题是析构函数不一定被调用,这导致我的购物车保持锁定状态,并最终导致超时错误。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

我认为你实际上想要去掉对AJAX请求的函数调用,这样你就不用担心自己锁定/解锁或取消之前的请求 - 只要你相对确定它们就做一个完成了调整数量。

我建议使用this jQuery plugin来限制或去除JavaScript函数调用(虽然jQuery实际上并不需要使用它,如果可用的话,它只能通过jQuery命名空间访问),假设你是如何制作你的AJAX的请求。

答案 1 :(得分:0)

我不得不说,如果你遇到了竞争条件,那么你在应用程序设计方面遇到了一些问题,这些问题可能会困扰你的应用程序一段时间,因为会话的并发访问会粉碎你的会话商店相对频繁

在我看来,最简单的方法是使用数据库表,而不是更新字段,而是为每个用户事件添加一行(因此,将插入增量操作,1,并且减量会插入一行-1)

通过这种方式,您只需执行总和操作即可统计您的计数,当用户结帐流程完成后,您可以清理购物车表中的整个订单。