Redis生成无规律不重复的纯数字券码

需求描述

在开发优惠券系统或票务系统的时候,经常要生成纯数字码,券码要求:12位纯数字,无规律,不重复。

下面我提供一种思路,利用redis的List数据类型,Lpop+Rpush 维护一个1万个码的队列

队列数据结构

保持1万个券码数量,可以根据项目实际情况自行调整

Array
(
    [0] => 478439938353
    [1] => 992919492490
    [2] => 476600175512
    [3] => 512596230643
    [4] => 627621923933
    [5] => 763100176075
    …………
    …………
    …………
    [9998] => 763100176032
    [9999] => 797543322210
)

用户端

用Lpop取出指定数量券码,因为Lpop具有原子性,在高并发的场景下,即使同一时间多个用户获取券码,也要按先后顺序一个个执行,这样就保证了每个用户获取出来的券码肯定不会重复的

/**
 * @从队列中取出指定数量的券码
 * @param $num   券码数量
 * @return array 返回券码数组
 */
function getCode($num){
	$codeArr=[];
	for($i=0;$i<$num;$i++){
		$tmpCode=$redis->LPOP($key);
		if(strlen($tmpCode)==10){
			$codeArr[]=$tmpCode;
		}
	}
	//如果队列中剩余券码数量不足,不足的部分要随机生成
	if(count($codeArr)<$num){
		$diff=$num-count($codeArr);
		for($i=0;$i<$diff;$i++){
			$code=rand(100000000000,999999999999);
			$codeArr[]=$code;
		}
	}
	return $codeArr;

}

定时脚本

  • 定时脚本每分钟执行一次,检查队列券码数量,消耗多个券码,就补充多少个券码进去。
  • 随机新生成的券码,要去数据库查下看是否已存在,如果已存在,需重新随机生成一个,再去数据库检查,直至查出有效券号为止
  • Rpush批量插入队列,提高操作效率

代码示例

$codeData=$redis->lRange($key,0,-1); //取出券码队列所有数据
$codeData=!is_array($codeData)?[]:$codeData;
$len=count($codeData);
$diff=10000-$len;//差多少个

$valid_arr=[];//有效核销码
if($diff>0){
    getValidCode($diff);
    $arr=array_merge([$key],$valid_arr);
    call_user_func_array(array($redis,"rpush"),$arr);//批量插入尾部,提高操作效率
}

//递归获取有效券号
function getValidCode($need_num){
    $filter_arr=[];
    for($i=0;$i<10;$i++){
        $code=rand(1000000000,9999999999);
        if(in_array($code,$codeData)){
            continue;
        }
        $filter_arr[]="'".$code."'";
        $valid_arr[]=$code;
    }
    if(count($filter_arr)==0){
        getValidCode($need_num);
        return;
    }
    //查找券码是否已使用
    $used_arr=[];
    $filter_str=implode(",",$filter_arr);
    $sql="select distinct `code` from `user_code` where `code` in ({$filter_str})";
    $tmpData=DB::query($sql);
    foreach($tmpData as $k=>$v){
        $used_arr[]=$v['code'];
    }
    unset($tmpData);
    $valid_arr=array_diff($valid_arr,$used_arr);//减掉数据库中已用的
    if(count($valid_arr)<$need_num){
        getValidCode($need_num);
    }
}

项目盘点

笔者所在企业的票务系统,使用这套券码解决方案,在年数据几千万条的情况下,已经稳定运行多年

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值