验证MySQL乐观锁与悲观锁
目标:验证谁更加能扛并发;
模拟场景,秒杀;
乐观锁实现
代码:
//悲观锁扣库存
public function test28(){
/**
* 1:查询库存数量
* 2:判断是否可以购买(不可购买则退出循环)
* 3:满足条件则减少对应库存,并记录拿到第多少个商品,提交并退出循环
* 4:否则重试第1步
*/
Db::startTrans();
$i=1;
do{
$stock=TStock::where('id','=',1)->find();
if ($stock->stock-1>=0){
//有货
//返回受影响条数
$re=TStock::where('id','=',1)->where('stock','=',$stock->stock)->setDec('stock',1);
if ($re===1){
//更新成功
TResult::insert(['value1'=>$stock->stock,'value2'=>$i]);//记录拿到第几个,第几次成功
Db::commit();
echo "第 $i 次成功!<br/>";
break;
}else{
//更新失败---重试
echo "第 $i 次重试中.....<br/>";
}
}else{
//没货了
Db::rollback();
echo "没货了<br/>";
break;
}
$i++;
if ($i>1000){
echo '老子不要了,太难抢了!<br/>';
Db::rollback();
break;//高并发时候,乐观锁性能消耗巨大,改善:将消息加入队列处理
}
}while(true);
}
ab测压结果:单纯乐观锁是个鸡肋
运行了好几次ab测压命令,才抢到15条,单纯乐观锁,基本没用,除非第一次就抢到,否者基本抢不到。就算配合消息队列处理,这也不是乐观锁本身扛并发了(难怪网上说成熟大网站才用乐观锁)。
悲观锁实现
//悲观锁实现
public function test29(){
/**
* 1:查询库存数量,并锁住记录
* 2:判断是否可以购买(不可购买则退出)
* 3:满足条件则减少对应库存,并记录拿到第多少个商品,提交
*/
Db::startTrans();
$stock=TStock::where('id','=',1)->lock(true)->find();
if ($stock->stock-1>=0){
TStock::where('id','=',1)->setDec('stock',1);
TResult::insert(['value1'=>$stock->stock]);
Db::commit();
echo "买到第 $stock->stock 个!<br/>";
}else{
Db::rollback();
echo '缺货<br/>';
}
}
测压命令
ab -n 260 -c 26 http://192.168.1.188:8042/index/test/test29