Laravel如何生成1000个唯一下载码并确保总数达标?
Laravel生成唯一6位下载码的优化实现
问题背景
我需要向数据库填充1000个唯一的6位下载码,目前在Laravel控制器中编写了生成代码,但未校验生成的码是否唯一。现有代码能计算需生成的数量并生成6位码保存,但存在重复风险,我自己写了一个校验逻辑,想找更优的实现方式。
现有控制器代码
// 计算已生成的下载码数量 $totalcount_generated_so_far = DownloadCode::count(); $quantity = 1000 - $totalcount_generated_so_far; if($quantity < 0) { return "无需生成!已有超过1000个下载码。"; } $object = new DownloadCode; for($i = 0; $i < $quantity; $i++) { $object = new DownloadCode; $length = 6; $keys = array_merge(range(1,9), range('A', 'Z')); $key1 = ""; // 注意:此处循环变量和外层for的$i重名,会导致逻辑错误 for($i=0; $i < $length; $i++) { $key1 .= $keys[mt_rand(0, count($keys) - 1)]; } $object->code_download = $key1; // 生成的6位码 $object->save(); } return $quantity . " 个下载码已生成。";
我的初步校验方案
// 校验唯一性 $uniq_test = DownloadCode::where('code_download',$key2)->first(); if($uniq_test) { $i--; // 重复则减少循环计数,重新生成 } else { $object->save(); }
这个方案存在几个问题:
- 每次生成后都要查询数据库,批量生成时效率低下
- 循环变量
$i重名会导致逻辑混乱 - 无法处理并发场景:如果多个请求同时生成相同的码,都通过了查询校验后插入,仍然会出现重复数据
更优实现方式
方案1:数据库唯一约束+异常捕获(推荐,保证绝对唯一)
首先给code_download字段添加唯一索引,从数据库层面阻止重复数据:
在迁移文件中修改字段定义:
Schema::create('download_codes', function (Blueprint $table) { // 其他字段... $table->string('code_download')->unique(); });
然后修改控制器代码,利用异常捕获处理重复情况:
// 计算需生成的数量 $existingCount = DownloadCode::count(); $quantity = 1000 - $existingCount; if ($quantity <= 0) { return "无需生成!已有超过1000个下载码。"; } $length = 6; $keys = array_merge(range(1, 9), range('A', 'Z')); $generated = 0; while ($generated < $quantity) { $code = ''; // 修正循环变量名,避免和外层冲突 for ($j = 0; $j < $length; $j++) { $code .= $keys[mt_rand(0, count($keys) - 1)]; } try { DownloadCode::create(['code_download' => $code]); $generated++; } catch (\Illuminate\Database\QueryException $e) { // 捕获唯一约束冲突异常,跳过重复码,继续生成 continue; } } return "已成功生成 {$quantity} 个唯一下载码。";
优点:数据库层面保证唯一性,即使并发请求也不会出现重复;代码逻辑简洁,无需提前查询所有现有码。
方案2:批量生成+内存去重(高效批量生成)
先查询所有已存在的码,在内存中过滤重复值,批量生成足够数量的唯一码后再插入数据库,减少数据库交互次数:
// 计算需生成的数量 $existingCount = DownloadCode::count(); $quantity = 1000 - $existingCount; if ($quantity <= 0) { return "无需生成!已有超过1000个下载码。"; } $length = 6; $keys = array_merge(range(1, 9), range('A', 'Z')); // 获取所有已存在的下载码 $existingCodes = DownloadCode::pluck('code_download')->toArray(); $newCodes = []; while (count($newCodes) < $quantity) { $code = ''; for ($j = 0; $j < $length; $j++) { $code .= $keys[mt_rand(0, count($keys) - 1)]; } // 检查是否已存在(包括已生成的新码) if (!in_array($code, $existingCodes) && !in_array($code, $newCodes)) { $newCodes[] = $code; } } // 批量插入数据库 DownloadCode::insert( collect($newCodes)->map(fn($code) => ['code_download' => $code])->toArray() ); return "已成功生成 {$quantity} 个唯一下载码。";
优点:减少数据库查询次数,批量插入效率更高;适合一次性生成大量码的场景。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

