为数据库生成随机 ID

Generating Random IDs for Database

我对一个项目有要求

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

我在这里尝试过解决方案: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 万分之一。这已经被高层认为是可以接受的。

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

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

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

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

绝对有必要限制自己只使用大写字母和数字吗?这将减少函数生成的唯一值的最大数量,而不是使用大写、小写、数字和符号。

你也可以考虑加密函数来增加随机性。

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

例如

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

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

如果您使用 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)

一般来说 - 当您无法检查数据库中的现有值时,总会有重复的可能。您所能做的就是将重复的可能性降低到足以满足您的用例的程度。这是 GUID.

背后的想法

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

类似于:

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