标签:解决方案 查询 inf innodb 百度搜索 技术 else 原因 库存
说明:当前测试为thinkphp5环境下的代码、不考虑用户uid问题,只考虑库存问题
准备:
1. 新建两个表(goods、orders)
CREATE TABLE `goods` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(30) NOT NULL DEFAULT ‘‘, `number` int NOT NULL DEFAULT ‘0‘, `price` int NOT NULL DEFAULT ‘1‘, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk CREATE TABLE `order` ( `id` int NOT NULL AUTO_INCREMENT, `uid` int NOT NULL DEFAULT ‘0‘, `goods_id` int NOT NULL DEFAULT ‘0‘, `number` int NOT NULL DEFAULT ‘0‘, `add_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk
2.插入两条商品数据
insert into `seo`.`ctx_goods` ( `name`, `number`, `price`) values ( ‘苹果手机‘, ‘10‘, ‘1‘); insert into `seo`.`ctx_goods` ( `name`, `number`, `price`) values ( ‘苹果电脑‘, ‘3‘, ‘2‘);
3.购买商品业务代码
public function order(){
$goods_id = 2;
$number = 1;
// 启动事务
Db::startTrans();
try{
$goods = Db::name(‘goods‘)->lock(true)->find($goods_id);
if($goods[‘number‘]>0){
$res1 = Db::name(‘goods‘)->where([‘id‘ => $goods_id])->setDec(‘number‘, $number);
$orderData = [
‘goods_id‘ => $goods[‘id‘],
‘uid‘ => 1,
‘number‘ => $number,
];
$res2 = Db::name(‘order‘)->insert($orderData);
if($res1 !==false && $res2){
// 提交事务
Db::commit();
exit(‘ok‘);
}else{
throw new \Exception(‘ 下单失败‘);
}
}else{
throw new \Exception(‘ 库存不足‘);
}
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
exit(‘error‘);
}
exit;
}
4. 测试产生超卖问题
注意:ab测试工具如果没有安装请百度搜索ab工具安装
ab -c500 -n800 -k http://seo_ctx.cn/portal/index/order
5. 结果
商品表数据

订单表数据

出现问题原因:
高并发,导致mysql查询同出来的数据一样,而在同一时间修改没有立即生效,之后这些修改都会被执行。
从而出现,库存只有3个却生成了3个以上的订单
解决方案:
1.设置数据库行锁
使用行锁,限制同一时间只能进行一个数据修改操作
将 $goods = Db::name(‘goods‘)->find($goods_id); 改成 $goods = Db::name(‘goods‘)->lock(true)->find($goods_id);
2.使用redis
用redis去维护库存
public function order(){
$goods_id = 2;
$number = 1;
$goods = Db::name(‘goods‘)->find($goods_id);
$redis = new \Redis();
$redis->connect(‘127.0.0.1‘, 6379);
if($redis->get(‘goodsNumber:‘.$goods_id)!==false){
//设置初始库存
$redis->set(‘goodsNumber:‘.$goods_id, $goods[‘number‘]);
}
// 启动事务
Db::startTrans();
try{
$remain_number = $redis->get(‘goodsNumber:‘.$goods_id);
if($remain_number>0){
$redis->decr(‘goodsNumber:‘.$goods_id, 1);
$res1 = Db::name(‘goods‘)->where([‘id‘ => $goods_id])->setDec(‘number‘, $number);
$orderData = [
‘goods_id‘ => $goods_id,
‘uid‘ => 1,
‘number‘ => $number,
];
$res2 = Db::name(‘order‘)->insert($orderData);
if($res1 !==false && $res2){
// 提交事务
Db::commit();
exit(‘ok‘);
}else{
throw new \Exception(‘ 下单失败‘);
}
}else{
throw new \Exception(‘ 库存不足‘);
}
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
exit(‘error‘);
}
exit;
}
标签:解决方案 查询 inf innodb 百度搜索 技术 else 原因 库存
原文地址:https://www.cnblogs.com/lauhp/p/14431949.html