美文网首页
商品秒杀问题解决方案

商品秒杀问题解决方案

作者: Stargazes | 来源:发表于2018-06-11 11:17 被阅读0次

    一、悲观锁

        悲观锁的方案采用的是排他读,同时只有一个进程能够操作当前的记录,事务在提交或回滚之后,锁会释放,其他的进程才能读取,在性能要求不严格的情况下,可直接使用改方案。要注意的是 SELECT … FOR UPDATE要尽可能的使用索引,以便锁定尽可能少的行数;排他锁是在事务执行结束之后才释放的,不是读取完成之后就释放,因此使用的事务应该尽可能的早些提交或回滚,以便早些释放排它锁。

    //0.开始事务 begin;/begin work;/start transaction; (三者选一就可以)

    //1.查询出商品信息 select status from t_goods where id=1 for update;

    //2.根据商品信息生成订单 insert into t_orders (id,goods_id) values (null,1);

    //3.修改商品status为2 update t_goods set status=2;

    //4.提交事务 commit;/commit work;

    二、乐观锁

        乐观锁的方案在读取数据是并没有加排他锁,而是通过一个每次更新都会自增的version字段来解决,多个进程读取到相同num,然后都能更新成功的问题。在每个进程读取num的同时,也读取version的值,并且在更新num的同时也更新version,并在更新时加上对version的等值判断。假设有10个进程都读取到了num的值为1,version值为9,则这10个进程执行的更新语句都是UPDATE goods SET num=num-1,version=version+1 WHERE version=9,然而当其中一个进程执行成功之后,数据库中version的值就会变为10,剩余的9个进程都不会执行成功,这样保证了商品不会超发,num的值不会小于0,但这也导致了一个问题,那就是发出抢购请求较早的用户可能抢不到,反而被后来的请求抢到了。

    1.查询出商品信息 select (status,status,version) from t_goods where id=#{id}

    2.根据商品信息生成订单

    3.修改商品status为2

    update t_goods set status=2,version=version+1 where id=#{id} and version=#{version};

    三、where条件下的原子操作

        每次对数量进行update操作时增加where数目大于0的条件,例如num为5,只要num>0 都能执行update语句

    四、redis watch方案

           Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

    类似mysql的乐观锁,客多个进程读取同一条记录,但是只能有一个进程事务执行成功,后面的执行都被中断。

    $num = $this->redis->get('num');

    $this->redis->watch('num');//watch相应的key值,

    $res = $this->redis->multi()->decr('num')->lPush('result',$num)->exec(); //执行key值的修改事务,decr($num),返回减一之后的数值

    五、redis list队列方案

        将商品信息保存在消息队列中,利用队列弹出操作的原子性,抢购时依次从list中pop出商品,不存在商品超卖的情况,缺点是商品多了话要把所有的商品信息存到内存上。

    六、基于redis decr返回值的方式,

        类似mysql的where操作。

    相关文章

      网友评论

          本文标题:商品秒杀问题解决方案

          本文链接:https://www.haomeiwen.com/subject/bmbceftx.html