关于订单号生成
list做mq的总结
使用方法
1. 生产者可以 lpush 写入消息,消费者可以 rpop 读取消息,也就是pull模式
2. 消费者可以使用 brpop 阻塞性读取消息,约等于服务器端的实时推送
3. 如何保证消息读取但未处理时,消费者程序异常宕机造成的消息丢失,答案:rpoplpush 或 brpoplpush ,即先从原队列中移除一个消息并插入到一个新队列,消费者处理完该消息后再从新队列中删除,相当于ack机制,避免消费者异常时消息丢失
//获取订单号 //下单类型 V:VIP; M:普通 // 由年月日时分秒+赛事活动编号【2位数】+-【商户编号/编码】+自动递进的【序号】
public static function getOrderNo($time, $m_no, $shop_id='', $order_type='M')
{ if( !in_array($order_type, ['M', 'V']) ) return [10102, config('code.10102')];
$d = date('YmdHis', $time);
$redis = Redis::connection(); i
f( $order_type == 'M' ){
$serial_num = $redis->lpop(self::ORDER_NO_LIST_COMMON_KEY); //重点
$order_no = $d.$m_no.$shop_id.$serial_num;
}elseif( $order_type == 'V' ){
$order_no = $redis->lpop(self::ORDER_NO_LIST_VIP_KEY); //重点
}
if( empty($order_no) ){ return [10103, config('code.10103')]; } return [200, $order_no]; }
以下是产生自动递进的序列号
<?php
namespace App\Console\Commands;
use App\Models\Orders;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use SebastianBergmann\Timer\Timer;
class CreateTradeNoCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'gym:create:trade:no';
/**
* The console command description.
*
* @var string
*/
protected $description = '创建订单号';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
Log::info($this->description.' start ');
$redis = Redis::connection();
$order_no_running_key = 'gym:order:no:create_running';
//普通用户配置
$order_common_num_key = 'gym:order:no:common:now_num';
$order_no_list_common_key= Orders::ORDER_NO_LIST_COMMON_KEY;//'gym:order:no:common:list';
$order_common_num = 0;
$order_no_common_exists_max = env('GYM_ORDER_COMMON_NO_EXISTS_MAX', 10000);
$order_no_common_min_need_run = env('GYM_ORDER_COMMON_NO_MIN_NEED_RUN', 5000);
//VIP用户配置
$order_vip_num_key = 'gym:order:no:vip:now_num';
$order_no_list_vip_key= Orders::ORDER_NO_LIST_VIP_KEY;
$order_vip_num = 10000;
$order_no_vip_exists_max = env('GYM_ORDER_VIP_NO_EXISTS_MAX', 1000);
$order_no_vip_min_need_run = env('GYM_ORDER_VIP_NO_MIN_NEED_RUN', 500);
$string = '';
if( ! $redis->exists($order_no_running_key) ){
$redis->setex($order_no_running_key, env('GYM_ORDER_NO_RUNNING_TIMES', 1200), 123);
$common_len = $redis->llen($order_no_list_common_key);
if( $common_len < $order_no_common_min_need_run ){
if( $redis->exists($order_common_num_key) ) $order_common_num = $redis->get($order_common_num_key);
$common_diff = $order_no_common_exists_max - $common_len;
$string .= ' run common no, start:'.$order_common_num.'; lens:'.$common_diff.';';
$push_array = [];
while ( $common_diff > 0 ){
$common_diff--;
$order_common_num++;
$push_array[] = $order_common_num;
}
$redis->rpush($order_no_list_common_key, $push_array);
$redis->set($order_common_num_key, $order_common_num);
$string .= ' common no end:'.$order_common_num.';';
}
$vip_len = $redis->llen($order_no_list_vip_key);
if( $vip_len < $order_no_vip_min_need_run ){
if( $redis->exists($order_vip_num_key) ) $order_vip_num = $redis->get($order_vip_num_key);
$vip_diff = $order_no_vip_exists_max - $vip_len;
$string .= ' run vip no, start:'.$order_vip_num.'; lens:'.$vip_diff.';';
$push_array = [];
while ( $vip_diff > 0 ){
$vip_diff--;
$order_vip_num++;
$push_array[] = $order_vip_num;
}
$redis->rpush($order_no_list_vip_key, $push_array);
$redis->set($order_vip_num_key, $order_vip_num);
$string .= ' vip no end:'.$order_vip_num.';';
}
$redis->del($order_no_running_key);
}
if( empty($string) ) $string = ' not run';
Log::info($this->description.' stop ', [$string]);
}
}