【问题标题】:Generate hundreds of random unique coupon codes and insert in database生成数百个随机唯一优惠券代码并插入数据库
【发布时间】:2020-08-30 18:04:11
【问题描述】:

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

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

substr(uniqid(), 0, 8)

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

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

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

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

因为我要生成许多唯一代码,而不仅仅是代码,然后我要将这些代码插入数据库中,我需要有最少数量的查询。

【问题讨论】:

  • 使用 time() + uniqid id 所以永远不会有重复
  • 我只有 8 个字符用于此目的,优惠券代码必须是 8 个字符。
  • 你可以在一个查询中从 db 中获取所有代码,然后检查代码(由管理员生成)in_array of codes from db
  • 您可以将代码设为您的 id,然后执行select count(*) from table,然后执行insert ignore ...,然后再次执行select count(*) from table,如果您插入的内容少于您需要的内容,请再次运行。这将比首先为可能数百万条记录执行whereIn 快得多,但是我建议使用Str::random(8) 来获取随机代码,因为它们比 uniqid 的子字符串更随机
  • @Odin Thunder,请考虑我可能有数千张优惠券,所以我认为这不是一个好的解决方案,我的 php 进程将面临内存泄漏。

标签: php laravel random unique


【解决方案1】:

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

function generateCode(){

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

【讨论】:

  • 我想,我自己实现的比这个功能更高效。它可能需要进行大量查询。
  • 相同,但更复杂
【解决方案2】:

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

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

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

    } while(!$new);

    return $coupon;
}

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

【讨论】:

  • 谢谢,但我认为我自己提供的解决方案性能更高。
【解决方案3】:

下面是一些可能有用的东西:

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 在插入和覆盖数据时会忽略重复键。这很有用,因为它避免了在插入之前进行可能很昂贵的查找,这应该返回受影响行的数量,即创建的新行。如果它没有设法插入所有需要的代码,那么它应该为剩余的代码再次运行它。这一切都假设code 是主键。

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

一些补充说明:

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

【讨论】:

  • 谢谢,我认为这是唯一比我自己的解决方案更方便、更高效的答案。
猜你喜欢
  • 2011-06-01
  • 2013-04-22
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多