目錄
前言:
1.隨機生成,核對user表是否已存在
代碼:
解析:
缺點:
2.建表建庫,每次從表中隨機抽取一條,用完時擴充
表結構
表視圖
代碼
解析
?缺點
結論:
前言:
目前使用了兩種生成唯一邀請碼的方法,都覺的不是很完美,有什么好的方法大姐可以交流一下,以下是我的代碼邏輯:
1.隨機生成,核對user表是否已存在
-
代碼:
function generateInvitationCode($i = 1)
{ $start = 10000;$end = 99999;// 如果循環了n次,仍然重復,則擴充范圍// 以避免10000-99999的數字全部都被占用了,在成無限循環$multiple = bcdiv($i, 50);if($multiple >= 1) {$start = $start . str_repeat(0, $multiple); // 拼接$multiple個0$end = $end . str_repeat(9, $multiple); // 拼接$multiple個9}// 生成隨機數$invitationCode = rand($start, $end); // 檢查邀請碼是否已經存在于數據庫中while (checkInvitationCodeExists($invitationCode)) {// 如果邀請碼已經存在,則重新生成$invitationCode = generateInvitationCode($i + 1);}return $invitationCode;
}
/*** 檢查不否已存邀請碼
*/
function checkInvitationCodeExists($invitationCode)
{$user = new User();$existingCode = $user->where('invitation_code', $invitationCode)->find();if ($existingCode){return true;}return false;
}
-
解析:
generateInvitationCode()
?函數用于生成邀請碼。它接受一個可選參數?$i
,表示循環次數。如果未提供參數,則默認為 1。在?
generateInvitationCode()
?函數中,我們首先定義了邀請碼的范圍,即從 10000 到 99999。如果循環次數?
$i
?大于 50,則我們需要擴充邀請碼的范圍。我們使用?bcdiv()
?函數計算?$i
?除以 50 的商,并將結果存儲在?$multiple
?變量中。然后,我們使用?str_repeat()
?函數將?$multiple
?個 0 和 9 分別拼接到?$start
?和?$end
?變量中。接下來,我們使用?
rand()
?函數在?$start
?和?$end
?之間生成一個隨機數,并將其存儲在?$invitationCode
?變量中。然后,我們使用?
checkInvitationCodeExists()
?函數檢查邀請碼是否已經存在于數據庫中。如果邀請碼已經存在,則我們遞歸調用?generateInvitationCode()
?函數,并將?$i
?參數加 1。最后,我們返回生成的邀請碼。
checkInvitationCodeExists()
?函數用于檢查邀請碼是否已經存在于數據庫中。它接受一個參數?$invitationCode
,表示要檢查的邀請碼。在?
checkInvitationCodeExists()
?函數中,我們首先創建一個新的?User
?對象。然后,我們使用?where()
?方法查詢數據庫中是否存在與?$invitationCode
?相匹配的邀請碼。如果存在,則返回?true
,否則返回?false
。
-
缺點:
可能會造成多次的user表查詢過于頻繁
2.建表建庫,每次從表中隨機抽取一條,用完時擴充
-
表結構
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for fa_activation_key
-- ----------------------------
DROP TABLE IF EXISTS `fa_activation_key`;
CREATE TABLE `fa_activation_key` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`status` int(2) NOT NULL DEFAULT 0 COMMENT '0未使用1已使用',PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `idx`(`id`) USING BTREE,INDEX `statusx`(`status`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 110000 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
-
表視圖
-
代碼
/*** 查找一個隨機邀請碼*/
function findKey(){return Db::name('activation_key')->where('status',0)->orderRaw('rand()')->limit(1)->value('id');
}/*** 生成邀請碼*/
function activationkey(){$key = findKey();if(empty($key)){// 如果邀請碼用完了,進行庫擴建$res = createActivationKey();if($res){// 擴建以后再隨機獲取一個$key = findKey();}}// 把邀請碼改為已使用狀態Db::name('activation_key')->where('id',$key)->update(['status'=>1]);return $key;
}/*** 建立邀請碼庫*/
function createActivationKey(){// 已使用完的邀請碼庫最大值,從這個值開始往上擴建$start = Db::name('activation_key')->order('id desc')->value('id');if(empty($start)){// 邀請碼庫為空從10000開始建庫$start = 10000;}else{// 邀請碼用完從最大值+1開始建庫$start = bcadd($start,1);}// 每次擴充99999個邀請碼$end = bcadd($start,99999);$arr = [];for ($i=$start; $i<=$end; $i++){$arr[] = ['id' => $i];}// 先把作廢的刪除掉Db::name('activation_key')->where('status', 1)->delete();// 批量插入邀請碼Db::name('activation_key')->data($arr)->limit(100)->insertAll($arr);return true;
}
-
解析
findKey()
?函數用于查找一個隨機邀請碼。它使用?Db::name('activation_key')
?查詢數據庫中狀態為 0 的邀請碼,并按隨機順序排序,使用?limit(1)
?限制只返回一個邀請碼。最后,使用?value('id')
?獲取邀請碼的 ID。
activationkey()
?函數用于生成邀請碼。它首先調用?findKey()
?函數查找一個隨機邀請碼。如果?findKey()
?返回的邀請碼為空,則表示邀請碼庫已經用完,需要擴建邀請碼庫。然后調用?createActivationKey()
?函數進行擴建。如果擴建成功,再次調用?findKey()
?函數查找一個隨機邀請碼。最后,將邀請碼的狀態更新為 1,表示已經使用過。
createActivationKey()
?函數用于建立邀請碼庫。它首先獲取當前已使用過的邀請碼庫的最大值,如果沒有找到,則從 10000 開始建立邀請碼庫。然后,每次擴充 99999 個邀請碼。接下來,創建一個包含所有邀請碼的數組,并先刪除狀態為 1 的邀請碼。最后,批量插入邀請碼。
-
?缺點
需要單獨的建表建庫,每次都需要調用mysql獲取,比直接隨機生成效率低,但相比第一種在后期會節約一定的時間,減少查詢次數
結論:
????????方法1,2各有優缺,但都不是很好的解決辦法,目前沒有想到其他的效率高的辦法,有好思路的朋友歡迎指點交流一下