原文地址:https://blog.csdn.net/hzbskak/article/details/103718369
首先看我改了之后的主要代码:
<?php
namespace app\index\controller;
use think\Db;
use think\Exception;
class Seckill{
public $price = 10;
public $user_id = 1;
public $goods_id = 1;
public $sku_id = 11;
public $number = 1;
private $redis = null;
public function __construct()
{
//模拟下单操作
//下单前判断redis队列库存量
$this->redis=new \Redis();
$this->redis->connect('127.0.0.1',6379);
$this->redis->auth(123456);
}
//主方法
public function go()
{
//取出用户
if (!$this->userPop())
{
$this->insertLog('no users buy');
return 'no users buy';
}
// 判断是否重复下订单
//sMembers返回集合中的所有的成员
if(in_array($this->user_id,$this->redis->sMembers('users_buy'))){
$this->insertLog($this->user_id.' repeat place order');
return $this->user_id.' repeat place order';
}
//检查库存 用于移除并返回列表的第一个元素。
$count = $this->redis->lPop('goods_store');
if(!$count){
$this->insertLog($this->user_id.' error:no store redis');
return $this->user_id.' error:no store redis';
}
// 开启事务 确保订单不会重复下
//生成订单
$order_sn=$this->build_order_no();
//放到这里
Db::startTrans();
try {
$order_rs = Db::name( 'order')
->insert([
'order_sn' => $order_sn,
'user_id' => $this->user_id,
'goods_id' => $this->goods_id,
'sku_id' => $this->sku_id,
'price' => $this->price
]);
//库存减少
$store_rs = Db::name( 'store')
->where( 'sku_id', $this->sku_id)
->setDec( 'number', $this->number);
Db::commit();
}catch (\Exception $e){
$this->insertLog($this->user_id .' 库存减少失败');
}
$this->redis->sAdd( 'users_buy', $this->user_id);
$this->insertLog($this->user_id .' 库存减少成功');
return;
}
//用户取出队列,返回用户id
public function userPop()
{
//命令用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回
return $this->user_id = $this->redis->rpoplpush('user_line_up','user_pop_queue');
// dump($this->redis->lRange("user_pop_queue",0,-1));
}
public function user()
{
//Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。
// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
dump($this->redis->lRange('user_line_up',0,-1));
}
public function clear()
{
// 命令用于清空当前数据库中的所有 key。
Db::name('log')->where("1=1")->delete();
Db::name('order')->where("1=1")->delete();
dump($this->redis->flushDB());
}
public function make()
{
echo $this->goodsStockAddQueue();
echo $this->userLineUp();
}
public function test()
{
dump( $this->redis->keys( '*'));
//Llen 命令用于返回列表的长度
dump( $this->redis->lLen( 'user_line_up'));
dump( $this->redis->lLen( 'goods_store'));
dump("goods_store:".$this->redis->lLen("goods_store"));
//用于返回 集合 KEY 的基数(集合中元素的数量)
dump( $this->redis->sCard( 'users_buy'));
}
//用户排队队列 $i即为user_id
public function userLineUp()
{
// 模拟用户二次下单
$num = [];
for ( $a=0;$a<2;$a++)
{
for ( $i=1;$i<1001;$i++)
{
array_push( $num, $i);
}
// 打乱排序
shuffle( $num);
}
for ( $i=0; $i< count( $num); $i++)
{
$this->redis->lPush( 'user_line_up', $num[$i]);
}
echo '用户排队数:'.$this->redis->lLen( 'user_line_up');
}
// 商品库存加入队列
public function goodsStockAddQueue()
{
$store = Db::name('store')->where('sku_id',$this->sku_id)->value('number');
$res = $this->redis->lLen('goods_store');
$count = $store-$res;
for ($i=0;$i<$count;$i++){
$this->redis->lPush('goods_store',1);
}
echo '商品剩余库存:'.$this->redis->llen('goods_store');
}
//生成唯一订单号
function build_order_no(){
return date('ymd').substr(implode(NULL,array_map('ord',str_split(substr(uniqid(),7,13),1))),10,8);
}
//记录日志
function insertLog($event,$type=0)
{
Db::name('log')->insert(['event'=>$event,'type'=>$type]);
}
}