PHP菜鸟博客_共同学习分享PHP技术心得【PHP爱好者】
解决高并发下insert到数据库表多条记录的问题
2021-2-12 菜鸟站长


1.有种业务场景比如微信会员注册,我们首先判断openid在数据库表中是否存在如果存在则提示已经存在,否则注册一条会员记录。thinkphp5代码如下




        $openid = '1111111';


        //查询openid是否存在


        $infoDb::table'test' )->where'openid'$openid )->find();


        if (!empty($info)) {


            echo 'openid已经存在!';


            die;


        }


        sleep(2); //模拟其他复杂业务逻辑处理增加耗时


        //insert插入


        $data['openid'] = $openid;


        $data['add_time'] = date'Y-m-d H:i:s'time() );


        $rs=Db::table'test' )->insert$data );


        print_r($rs);


        die;



我相信这样的场景有很多,而且大家也都写过类似的代码,而且看上去也在正常不过了,但是这样的代码在高并发的情况下会插入数据库表多条记录。



我用apache jmeter压测工具模拟50个并发请求,然后发现数据库进来25条记录。问题出现了。


1.jpg


 



上面代码sleep(2);是为了模拟注册过程中其他的一些业务逻辑处理。如果没有sleep(2),我用apache jmeter工具并发请求,也没有发现出来多条记录。那么如果解决上面的问题呢?引入mysql锁的概念。锁必须与事务配合使用下面是改进的代码 :



 




        $openid = '1111111';


        // 启动事务


        $trans_result = true;


        Db::startTrans();


        try { 


            //查询openid是否存在  ,//查询之后锁住该条记录让其他程序无法修改,直到事务提交释放锁


            $info = Db::table'test' )->locktrue )->where'openid'$openid )->find();


            if ( !empty$info ) ) {


                //手动抛出异常


                throw new \Exception'openid已经存在!' );




            }


            sleep2 );


            //模拟其他复杂业务逻辑处理增加耗时


            //insert插入


            $data['openid'] = $openid;


            $data['add_time'] = date'Y-m-d H:i:s'time() );


            $rs = Db::table'test' )->insert$data );


            if ( !$rs ) {


                //手动抛出异常


                throw new \Exception'insert 失败!' );


            }


            Db::commit();


        } catch ( \Exception $e ) {


            // 回滚事务


            Db::rollback();


            $trans_result = false;


            echo  $msg = $e->getMessage();


        }


        //如果失败


        if ( !$trans_result ) {


            echo '执行失败0'.$msg;




        }else {


            echo '执行成功1';


        }


     



 


2.jpg3.jpg4.jpg


 



总结,把查询语句和插入语句放到一个事务里面,解决不了并发插入多条记录的问题,还需要配置使用锁,锁的意思就是当n个请求同时过来只有一个人能获取到锁,并且锁住那条记录,其他程序无法获取到就会报错,也就是这么多并发请求,最终只有一个能够执行成功。当然此案例也可以使用mysql表openid字段设置唯一索引,50个并发最终也会只有一个能成功,其他的同样会抛出sql异常。

发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容