php 如何在laravel中为每个用户生成唯一的随机值并将其添加到数据库中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28524290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 23:55:05  来源:igfitidea点击:

How to generate unique random value for each user in laravel and add it to database

phpmysqllaravelrandomeloquent

提问by Nasif Md. Tanjim

I am developing a event organization website. Here when the user registers for an event he will be given a unique random number(10 digit), which we use to generate a barcode and mail it to him. Now,

我正在开发一个活动组织网站。在这里,当用户注册活动时,他将获得一个唯一的随机数(10 位),我们用它来生成条形码并将其邮寄给他。现在,

  1. I want to make the number unique for each registered event.
  2. And also random
  1. 我想让每个注册事件的编号都是唯一的。
  2. 还有随机的

One solution is to grab all the random numbers in an array and generate a random number using Php rand(1000000000, 9999999999) and loop through and check all the values. Grab the first value that doesn't equal to any of the values in the array and add it to the database.

一种解决方案是获取数组中的所有随机数并使用 Php rand(1000000000, 9999999999) 生成一个随机数,然后循环检查所有值。获取不等于数组中任何值的第一个值并将其添加到数据库中。

But I am thinking that there might be a better solution to this. Any suggestion?

但我认为可能有更好的解决方案。有什么建议吗?

回答by Abhijeet Ashok Muneshwar

You can use php's uniqid()function to generate a unique ID based on the microtime (current time in microseconds)

可以使用php的uniqid()函数根据微时间(当前时间以微秒为单位)生成唯一ID

Example:

例子:

<?php
echo uniqid();
?>

Output:

输出:

56c3096338cdb

回答by Joel Hinz

Your logic isn't technically faulty. However, if your application attracts lots of users, fetching all of the random numbers may well become unnecessarily expensive, in terms of resources and computation time.

你的逻辑在技术上没有问题。但是,如果您的应用程序吸引了大量用户,那么在资源和计算时间方面,获取所有随机数可能会变得不必要地昂贵。

I would suggest another approach, where you generate a random number and then check it against the database.

我会建议另一种方法,您可以生成一个随机数,然后根据数据库对其进行检查。

function generateBarcodeNumber() {
    $number = mt_rand(1000000000, 9999999999); // better than rand()

    // call the same function if the barcode exists already
    if (barcodeNumberExists($number)) {
        return generateBarcodeNumber();
    }

    // otherwise, it's valid and can be used
    return $number;
}

function barcodeNumberExists($number) {
    // query the database and return a boolean
    // for instance, it might look like this in Laravel
    return User::whereBarcodeNumber($number)->exists();
}

回答by Pavan Jiwnani

Looping through the array won't be that efficient. If your database becomes too large then it slow down the entire process and also there might be a rare situation when 2 threads are looping through the array for the same random number and it will be found available and return same number to both the tickets.

循环遍历数组不会那么有效。如果您的数据库变得太大,那么它会减慢整个过程,并且当 2 个线程循环遍历数组以获取相同的随机数时,可能会出现一种罕见的情况,并且会发现它可用并向两个票证返回相同的数字。

So instead of looping through the array you can set the 10 digit registration id as primary key and instead of looping through the array you can insert the registration details along with randomly generated number, if the database insert operation is successful you can return the registration id but if not then regenerate the random number and insert.

因此,您可以将 10 位注册 id 设置为主键,而不是遍历数组,而不是遍历数组,您可以插入注册详细信息以及随机生成的数字,如果数据库插入操作成功,您可以返回注册 id但如果不是,则重新生成随机数并插入。

Alternate solution which will be more effective Instead of 10 digit random numbers you can use timestamp to generate a 10 digit unique registration number and to make it random you can randomize the first 2 or 3 digits of the timestamp

更有效的替代解决方案代替 10 位随机数,您可以使用时间戳生成 10 位唯一注册号,并使其随机化,您可以随机化时间戳的前 2 位或 3 位数字

回答by possemedia

To avoid the problem of having to check to see if a matching code exists every time a new one is created, I just catch MySQL's duplicate record exception (error code 1062). If that error is caught, I just call the function again until the save is successful. That way, it only has to generate a new code if it collides with an existing one. Runs a lot faster -- but obviously gets a bit slower as your number of users approaches the number of possible barcodes.

为了避免每次创建新代码时都必须检查是否存在匹配代码的问题,我只捕获 MySQL 的重复记录异常(错误代码 1062)。如果该错误被捕获,我只需再次调用该函数,直到保存成功。这样,如果它与现有代码发生冲突,它只需生成一个新代码。运行速度要快得多——但随着用户数量接近可能的条形码数量,显然会变慢一些。

function generateBarcode($user_id) {
    try {
        $user = User::find($user_id);
        $user->barcode = mt_rand(1000000000, 9999999999);
        $user->save();

    } catch (Exception $e) {
        $error_info = $e->errorInfo;
        if($error_info[1] == 1062) {
            generateBarcode($user_id);
        } else {
            // Only logs when an error other than duplicate happens
            Log::error($e);
        }

    }
}

So just loop through all the users you want to assign a code to:

因此,只需遍历您要为其分配代码的所有用户:

foreach(User::all() as $user) {
    generateBarcode($user->id);
}

You could also add some logic to escape the function loop if a maximum number of attempts are made, but I've never bothered because collisions are unlikely.

如果尝试达到最大次数,您还可以添加一些逻辑来逃避函数循环,但我从来没有打扰过,因为不太可能发生冲突。

回答by Hadi Note

This is good:

这很好:

do {
   $refrence_id = mt_rand( 1000000000, 9999999999 );
} while ( DB::table( 'transations' )->where( 'RefrenceID', $refrence_id )->exists() );

回答by Takamura

<?php
declare(strict_types=1);

namespace App\Helpers;


use App\Exceptions\GeneratorException;

class GeneratorHelper
{
    public static $limitIterations = 100000;

    /**
     * @param string $column
     * @param string $modelClass
     * @return string
     * @throws GeneratorException
     */
    public static function generateID(string $modelClass, string $column): string
    {
        return self::run(
            $modelClass,
            $column,
            self::IDGenerator(),
            'Generation id is failed. The loop limit exceeds ' . self::$limitIterations
        );
    }

    /**
     * @param string     $modelClass
     * @param string     $column
     * @param \Generator $generator
     * @param string     $exceptionMessage
     * @param array      $whereParams
     * @return string
     * @throws GeneratorException
     */
    protected static function run(string $modelClass, string $column, \Generator $generator, string $exceptionMessage, array $whereParams = []): string
    {
        try {
            foreach ($generator as $id) {
                $query = $modelClass::where([$column => $id]);
                foreach ($whereParams as $param) {
                    $query->where(...$param);
                }
                if (!$query->first()) {
                    return $id;
                }
            }
        } catch (\Throwable $e) {
            $exceptionMessage = $e->getMessage();
        }

        throw new GeneratorException($exceptionMessage);
    }

    protected static function IDGenerator(): ?\Generator
    {
        for ($i = 1; $i <= self::$limitIterations; $i++) {
            yield (string)random_int(1000000000, 9999999999);            
        }
        return null;
    }
}

sample usage

示例用法

$card->number = GeneratorHelper::generateID(Card::class, 'number');

回答by Naqib Faiyaz

One Solution could be like this:

一种解决方案可能是这样的:

use Illuminate\Support\Facades\Validator;
private function genUserCode(){
    $this->user_code = [
        'user_code' => mt_rand(1000000000,9999999999)
    ];

    $rules = ['user_code' => 'unique:users'];

    $validate = Validator::make($this->user_code, $rules)->passes();

    return $validate ? $this->user_code['user_code'] : $this->genUserCode();
}

Its generating a random number between 1000000000 and 9999999999. After that, it validates the number against the table. If true then it returns the number, otherwise runs the function again.

它生成一个介于 1000000000 和 9999999999 之间的随机数。之后,它会根据表验证该数字。如果为真,则返回数字,否则再次运行该函数。

回答by Mladen Janjetovic

I made something like this

我做了这样的事情

/**
 * Generate unique shipment ID
 * 
 * @param int $length
 * 
 * @return string
 */ 
function generateShipmentId($length)
{
    $number = '';

    do {
        for ($i=$length; $i--; $i>0) {
            $number .= mt_rand(0,9);
        }
    } while ( !empty(DB::table('shipments')->where('id', $number)->first(['id'])) );

    return $number;
}