生成数百个随机唯一优惠券代码并插入数据库

Generate hundreds of random unique coupon codes and insert in database

我正在使用 PHP laravel 7 我有一张优惠券 table,其中有一个名为代码的字段,这个代码是 8 个字符(数字和字符) 此代码在优惠券记录中应该是唯一的, 在管理面板中,我有一个供管理员用户使用的按钮,他可以单击该按钮并生成任意数量的优惠券。 我将与您分享我想到的最佳解决方案,并询问您是否有更好、更高性能的解决方案。

我将使用以下函数在我的 php 代码中生成唯一字符串:

substr(uniqid(), 0, 8)

然后我将执行查询以检查我的 table 中是否有任何优惠券,它的代码等于我新生成的代码之一

$model->newQuery()->whereIn('code', $generated_codes)->get();

如果结果列表为空,那很好,我会将我的所有代码插入数据库。如果列表不为空,我将从我生成的代码中删除重复代码,并且再次根据重复代码的数量再次生成新代码并再次重复该过程,只要 none 的生成代码存在于数据库中 然后我将它们插入数据库。

我的问题与这个问题不同: PHP: How to generate a random, unique, alphanumeric string?

因为我要生成很多独特的代码,而不仅仅是代码,然后我要把这些代码插入数据库,我需要有最少数量的查询。

您可以使用此类功能来获取唯一的优惠券代码。

function generateCode(){

    $code = substr(uniqid(), 0, 8);
    $exists = YourModel::where('code', $code)->count();
    if($exists > 0){
        $this->generateCode();
    }
    return $code;
}

你可以使用firstOrCreate(),但实际上它可能会执行很多查询。希望它能帮助你找到好的解决方案

public function initCoupon()
{
    $code = substr(uniqid(), 0, 8);
    $new = false;
    do {

        $coupon = CouponModel::firstOrCreate(compact('code'));
        $new = $coupon->wasRecentlyCreated

    } while(!$new);

    return $coupon;
}

比你可以设置额外的优惠券数据

这里有一些可能有用的东西:

function generateRandomCodes($number) {
    $codes = Collection::times($number, function () { Str::random(8); });

    $affected = DB::table('your_table')
       ->insertOrIgnore($codes->map(function ($code) {
             return [ 'code' => $code, /* more fields? */ ];
       });
    if ($affected < $number) {
        generateRandomCodes($number-$affected);  
    }
}

insertOrIgnore 会在插入和覆盖数据时忽略重复键。这很有用,因为它避免了插入之前的查找,这可能是昂贵的,这个 shouldreturn affected 行的数量,即新创建的行。如果它没有设法插入所有需要的代码,那么它 应该 运行 再次插入剩余的代码。这一切都假设 code 是主键。

我自己没有对此进行测试,因此我建议您在将其用于任何生产代码之前对其进行测试。

一些补充说明:

Str::random 在内部使用来自 random_bytes 的 base64 编码字符串,它在密码学上是安全的(尽管不确定它的 base64 版本在技术上是否算作安全的,也不确定最终结果是否真的安全) .这意味着有 62^8 = 2*10^14 种组合可以得到字符(+、= 和 / 被删除)。这是一个非常高的数字,在您生成这些数字的大约 10%(大约 2*10^13)之前,您不应该真正期望发生碰撞 然而 这假设您是将它们存储在数据库的 区分大小写 列中,默认情况下,字符串列 区分大小写,这会将您的独特组合减少大约三分之二(这仍然是一个相当大的数字)意味着你真的不需要多次调用这个函数,除非你真的是 "lucky"