【问题标题】:Generating Random IDs for Database为数据库生成随机 ID
【发布时间】:2018-08-16 14:49:47
【问题描述】:

我对一个项目有要求

  • 我需要生成唯一 ID。
  • ID 必须大写。
  • 我无法检查数据库以查看之前是否使用过 ID。

我们预计每个月都会有数百万条记录添加到数据库中。

我在这里尝试过解决方案:PHP: How to generate a random, unique, alphanumeric string? 虽然它们一开始似乎有效,但我的测试表明随着时间的推移会有重复。

现在我正在考虑使用带前缀的 uniqid。我发现使用不带前缀的 uniqid 的问题是,当同时请求同时进入服务器时会产生重复。我希望使用前缀可以解决这个问题。
我正在考虑使用这个功能:

private function generate_id()
{
    $alpha_numeric = 'ABCDEFGHIJKLMNPQRSTUVWXYZ0123456789';
    $max = strlen($alpha_numeric);
    $prefix = '';

    for ($i = 0; $i < 5; $i++)
    {
        $prefix .= $alpha_numeric[random_int(0, $max - 1)];
    }
    return strtoupper(uniqid($prefix));
}

前缀是 5 个字符的字母数字字符串。这足以满足我的要求吗?

*****编辑*****

按照建议使用 UUID 是限制冲突机会的最佳方法,但已决定采用上述方法,但将前缀增加到 7 个字符。如果在同一毫秒内生成两个 ID,则发生冲突的可能性约为 830 万分之一。上级认为这是可以接受的。

【问题讨论】:

  • 也许你可以使用类似这样的库:github.com/ramsey/uuid 来呈现 UUID?
  • 也许,您可以使用数组或类似的东西来识别已使用的 id。
  • @Comp 那么 OP 将如何 a)在内存中保留一个 100,000,000 条目数组,然后 b)在不查询数据库的情况下加载它
  • 如果您使用 MSSQL 服务器作为数据库引擎,您可以使用 GUID(全局唯一标识符)方法使用 NEWID() 函数。请在此处阅读更多信息:docs.microsoft.com/en-us/sql/t-sql/functions/…
  • @RiggsFolly 没有查询会去,但是是的,数组太大了,我没想到。

标签: php string random uniqueidentifier unique-key


【解决方案1】:

如果您使用 Composer 或外部库,请参阅 https://github.com/ramsey/uuid

或者这个功能可以满足你的需要。满足您的需求strtoupper 结果:

/**
 * generate
 *
 * Returns a version 4 UUID
 *
 * @access public
 * @return string
 */
public static function generate()
{
    $data = openssl_random_pseudo_bytes(16);

    $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
    $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)

【讨论】:

    【解决方案2】:

    您是否考虑过在数据库中使用唯一键来强制唯一性?在这种情况下,您不必自己检查重复项,而是会生成唯一值并尝试将记录插入数据库中,直到成功为止。

    如果 MySQL 则阅读此内容 - Using MySQL UNIQUE Index To Prevent Duplicates。如果没有,请查看您选择的数据库的文档。

    uniquid不保证返回值的唯一性!使用 more_entropy 设置为 TRUE 的函数来增加唯一值的机会。

    return strtoupper(uniqid($prefix), true);
    

    绝对有必要将自己限制为仅使用大写字母和数字吗?与使用大写、小写、数字和符号相反,这将减少从函数生成的唯一值的最大数量。

    您还可以考虑使用加密函数来增加随机性。

    【讨论】:

    • 是的,我们将这样做。但是,这个系统的设计方式是在插入数据库之前向服务器发出请求并返回给客户端。
    【解决方案3】:

    如果您使用的是 PHP7,请查看http://php.net/manual/en/function.random-bytes.php

    例如

    <?php
    echo strtoupper(bin2hex(random_bytes(32)));
    ?>
    

    应该足够独特以满足您的要求,如果您觉得需要,请使用更多字节。

    【讨论】:

      【解决方案4】:

      一般来说 - 当您无法检查数据库中的现有值时,总会有重复的可能。您所能做的就是将重复的概率降低到对您的用例而言足够低的程度。这是GUID 背后的想法。

      如果您真的无法访问数据库并且您真的仅限于大写字符,那么我建议您使用uniqid 函数生成 GUID,然后删除您不想要的字符并转换为大写。如果您担心可能会出现重复,请连接两个或多个 GUID 以降低这种可能性。

      类似:

      $unique_string = str_replace(".", "", strtoupper(uniqid(uniqid(uniqid(), true), true)));
      

      【讨论】:

        猜你喜欢
        • 2013-04-24
        • 1970-01-01
        • 2015-01-21
        • 2020-11-03
        • 1970-01-01
        • 2011-10-18
        • 2019-07-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多