Mysql之事务(并发)初体验

先声明本人菜鸟,不喜勿喷。

模拟应用场景是,支付下单,减少库存。

我建了三个表,goods、orders、logs 都是用的InnoDB引擎,不然不支持事务

goods里面的字段,id,name,price,stock(库存)
orders里面有 id,uid,ordersn,good_id,createtime
logs 里面有 id,status,uid

以上表的id都是自增长的主键

用的tp3.2测试的

插入一条数据到goods

    public function addgoods(){
        $data = array(
            'name' => '小米手机',
            'price' => 100,
            'stock' => 10
        );
        M('goods')->add($data);
    }

然后就是弄一个创建订单的方法createOrder,同时更新了库存,在弄一个call调用

简单的写了下这个下单的过程,可以理解为,就一个insert一个update 不带事务

    public function call(){
        $this->createOrder(1, 1);
    }

    public function createOrder($uid,$goodid){

        $good = M('goods')->find(1);
        if(!$good['stock'] > 0) {
            return false;
        }
        $data = array(
            'ordersn' => NOW_TIME.rand(1000000,9999999),
            'good_id' => $goodid,
            'createtime' => NOW_TIME,
            'uid' => $uid
        );
        $orderid = M('orders')->add($data);

        $stock = $good['stock'] - 1;
        $goodupdate = M('goods')->where('stock > 0 and id = 1' )->save(array('stock' => $stock));

        if($orderid && $goodupdate){
            $status = '成功';
        }else{
            $status = '失败';
        }
       return M('logs')->add(array('uid' =>$uid,'status' => $status));
    }

然后下载了一个叫ab的所谓web性能测试工具

我们就调用call方法 100次试试。

发现库存确实是0了(减少了10个),但是orders表里面有47条数据。我滴个龟龟。。好吓人
如果说这是一个秒杀,100个人同时去买,有47个订单是成功的。但是库存却只有10个。
如果并发更高呢?后果不堪设想。。

我们加添加事务试试。。

    public function createOrder($uid,$goodid){

        M()->startTrans();
        $good = M('goods')->find(1);
        if(!$good['stock'] > 0) {
            return false;
        }
        $data = array(
            'ordersn' => NOW_TIME.rand(1000000,9999999),
            'good_id' => $goodid,
            'createtime' => NOW_TIME,
            'uid' => $uid
        );
        $orderid = M('orders')->add($data);

        $stock = $good['stock'] -1;
        $goodupdate = M('goods')->where('stock > 0 and id = 1' )->save(array('stock' => $stock));

        if($orderid && $goodupdate){
            $status = '成功';
            M()->commit();
        }else{
            $status = '失败';
            M()->rollback();
        }
       return M('logs')->add(array('uid' =>$uid,'status' => $status));
    }

加了这几句, 其他代码也没变

 M()->startTrans();   
 M()->commit();  
 M()->rollback();  

库存还原到10个,清空logs和orders,再跑一边看结果吧。

库存依然正常到0了,但是orders有28条数据,啥情况。。。是不是事务写错了,还是tp里面的事务有bug?这不是闹眼子吗。。

然后我特意去测试tp的事务,写一个update然后回滚,看行不行。。结果是可以的。。

那么我这个代码到底哪里出了问题。。写了事务咋还不行?

原来忘记了一个大问题,那就是没锁表。。。

我们把

    $good = M('goods')->find(1);

修改为

    $good = M('goods')->lock(true)->find(1);
   // lock相当于是加了个for update 我们用的InnoDB支持行级锁

再试试。。

库存正常为0,orders和logs都只有10条数据了。应该就正常了。。
我们在试试1000个并发,依然是稳稳的10条数据。。

如果只是小量的并发,用事务和锁表完全可以解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值