按照随机策略生成一个不重复的邀请码(字母+数字),既要不重复又要保证性能。每个用户对应一个邀请码,必须做到唯一性。邀请码的需要手动输入所以长度不能太长,同时不能让用户猜到邀请码的生成逻辑,所以邀请的生成逻辑也必须要随机 。
一、使用 NanoID或自有规则算法生成(非并发场景)
根据生成库生成邀请码,在查询数据库,如果存在就继续生成直到成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//https://github.com/ai/nanoid //composer require hidehalo/nanoid-php use Hidehalo\Nanoid\Client; use Hidehalo\Nanoid\GeneratorInterface; /** * 生成邀请码 * @return string */ function createInviteCode(){ $client = new Client(); do{ $code = $client->formattedId('123456789ABCDEFGHJKLMNPQRSTUVWXYZ',5); //查询库里存在不。 $existed_count = DbModel::where('invite_code',$code)->count(); }while($existed_count > 0); return $code; } |
二、使用Redis生成唯一邀请码
方案来源:https://blog.csdn.net/JSPSEO/article/details/125359454
一个自增点会导致数量连续有规律,那么我们可以设置多个池子,每个池子维护一个自增点,随机去一个池子通过自增id生成,就能够做到随机了。因为邀请码的长度有限制,所以我们需要算出来邀请码最大的范围值有多少,然后将最大的范围值分成若干个池子。
6位(数字+字母)长度的邀请码,根据可取字符的数量,我们将邀请码的形式设置为36进制数,这样邀请码的范围值就是为000000~zzzzzz,也就是等于十进制的2176782335,相当于我们最多能够生成2176782335个邀请码。如果此数量不满足业务上的需求,可以根据业务要求适当增删。我们假设每个池子能够存储邀请码的数量为10000个,则会有217678个池子。我们每个自增点就等于:邀请码 = (池子number * 10000 + 自增点)转成32进制 的字符串。

要注意红色字体,每个池子有最大自增点限制,为该池子能够存储邀请的最大数量。通过上述过程就能做到生成一个唯一且无明显规律的邀请码。当然要想最大程度无规律的话,可以将前几个池子给剔除掉,这样子就不会出现000001这样子的邀请码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
<?php class Code{ protected Redis $redis; private $codeIncrementSet = 'code_increment_set'; private $codeAvailableSet = 'code_available_set'; public function __construct(){ $this->redis = new Redis(); $this->init(); } //初始化 private function init(){ if (0 === $this->redis->exists($this->codeIncrementSet)){ //添加1-217678序号的池子,并且自增点设置为0 $this->redis->zAdd($this->codeIncrementSet,array_fill(1,217678),0); //保存1-217678序号的可用池子 $this->redis->sAddArray($this->codeAvailableSet,range(1,217678)) } } public function getCode(){ //随机取一个可用的邀请码池子 if (is_null($index = $this->redis->srandmember($codeAvailableSet))){ throw new BusinessException('可用邀请码码数为空'); } //获取对应需要池子的自增点 $increment = (int)$this->redis->zScore($this->codeIncrementSet,$index) //计算code值 $number = (int)index * 10000 + $increment; //维护自增点 $this->redis->zIncrBy($this->codeIncrementSet,1,$index); //该池子被用完了 if (9999 === $increment){ $this->redis->sRem($this->codeAvailableSet,$index); } //返回36进制的邀请码,用0部位 return str_pad(base_convert($number, 10, 36), 6, '0', STR_PAD_LEFT); } } |
如何做到高性能
生成用户邀请码是一个频繁的操作,如果每次实时生成的话性能会比较低。可用利用空间换时间的思维。预先生成一批邀请码然后在需要的时候直接拿出来用即可。这种思路在开发中很常见,异步处理,用空间换取时间。通过这种方式就能快速的生成邀请码。
Comments | NOTHING