如何在MySQL中生成唯一ID?

时间:2009-09-23 17:51:04

标签: php sql mysql

我正在使用PHP和MySQL编写脚本,我希望得到一个 唯一ID(由字符串组成:大写字母和小字符 带数字的字母):gHYtUUi5b。 我发现PHP中的许多函数可以生成这样的数字,但我担心如何确保id是唯一的!

UPDATE :uuid很长,我的意思是这样的id:(P5Dc)一个11个字母数字字符。

16 个答案:

答案 0 :(得分:52)

我使用UUID()创建一个唯一值。

示例:

insert into Companies (CompanyID, CompanyName) Values(UUID(), "TestUUID");

答案 1 :(得分:20)

您可能喜欢我们这样做的方式。我想要一个看似“随机”的可逆唯一代码 - 一个相当常见的问题。

  • 我们输入一个输入数字,如1,942。
  • 将其填入字符串:“0000001942”
  • 将最后两位数字放在前面:“4200000019”
  • 将其转换为数字:4,200,000,019

我们现在有一个号码在通话之间变化很大,保证不到10,000,000,000。这不是一个糟糕的开始。

  • 将该数字转换为Base 34字符串:“2oevc0b”
  • 用'y'替换任何零,用'z'替换任何零:“2oevcyb”
  • 升档:“2OEVCYB”

选择基数34的原因是我们不担心0 / O和1/1碰撞。现在,您有一个短随机密钥,可用于查找LONG数据库标识符。

答案 2 :(得分:13)

程序化方式可以是:

  • 在字段中添加UNIQUE INDEX
  • 在PHP中生成随机字符串
  • PHP中的
  • 循环(while(!DO_THE_INSERT))
    • 生成另一个字符串

<强> 注意:

  • 这可能很脏,但具有与DBMS无关的优势
  • 即使您选择使用DBMS特定的唯一ID生成器功能(UUID等) 使用索引确保字段HAS为独特是最佳做法
  • 循环在统计上根本不执行,仅在插入失败时输入

答案 3 :(得分:6)

如何生成unique_ids是一个有用的问题 - 但是当你生成它们时,你似乎正在对进行反效果假设!

我的观点是,您在创建行时不需要生成这些唯一ID,因为它们基本上与所插入的数据无关。

我所做的是预先生成唯一ID以供将来使用,这样我就可以享受自己的美好时光并绝对保证它们是独一无二的,并且在插入时无法完成任何处理。

例如,我有一个带有order_id的订单表。当用户输入订单时,会立即生成此ID,永久递增1,2,3等。用户无需查看此内部ID。

然后我有另一个表 - unique_ids with(order_id,unique_id)。我有一个每天晚上运行的例程,它会为此表预加载足够多的unique_id行,以覆盖可能在接下来的24小时内插入的订单。 (如果我在一天内获得10000份订单,​​我就会遇到问题 - 但这将是一个很好的问题!)

这种方法保证了唯一性,并且可以将任何处理负载从插入事务转移到批处理例程中,而不会影响用户。

答案 4 :(得分:4)

如果您使用版本高于5.7.4的MySQL,则可以使用新添加的RANDOM_BYTES函数:

 SELECT TO_BASE64(RANDOM_BYTES(16));

这会产生一个随机字符串,例如GgwEvafNLWQ3+ockEST00A==

答案 5 :(得分:3)

使用UUID function

我不知道PHP中用于生成唯一值的过程的来源。如果它是库函数,它们应该保证您的值非常独特。签入文档。您应该始终使用此功能。例如,如果您使用PHP函数生成唯一值,然后您决定使用MySQL函数,则可以生成已存在的值。在这种情况下,在列上放置UNIQUE INDEX也是一个好主意。

答案 6 :(得分:1)

对于唯一性,我所做的是使用Unix时间戳并附加一个随机字符串并使用它。

答案 7 :(得分:1)

DELIMITER $$

USE `temp` $$

DROP PROCEDURE IF EXISTS `GenerateUniqueValue`$$

CREATE PROCEDURE `GenerateUniqueValue`(IN tableName VARCHAR(255),IN columnName VARCHAR(255)) 
BEGIN
    DECLARE uniqueValue VARCHAR(8) DEFAULT "";
    DECLARE newUniqueValue VARCHAR(8) DEFAULT "";
    WHILE LENGTH(uniqueValue) = 0 DO
        SELECT CONCAT(SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1),
                SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', RAND()*34+1, 1)
                ) INTO @newUniqueValue;
        SET @rcount = -1;
        SET @query=CONCAT('SELECT COUNT(*) INTO @rcount FROM  ',tableName,' WHERE ',columnName,'  like ''',newUniqueValue,'''');
        PREPARE stmt FROM  @query;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
    IF @rcount = 0 THEN
            SET uniqueValue = @newUniqueValue ;
        END IF ;
    END WHILE ;
    SELECT uniqueValue;
    END$$

DELIMITER ;

将存储过程称为GenerateUniqueValue(&#39; tableName&#39;,&#39; columnName&#39;)。这将每次给你一个8位数的独特角色。

答案 8 :(得分:0)

以下仅供参考数字唯一随机ID ...

它可能对你有帮助......

$query=mysql_query("select * from collectors_repair");
$row=mysql_num_rows($query);
$ind=0;
if($row>0)
{
while($rowids=mysql_fetch_array($query))
{
  $already_exists[$ind]=$rowids['collector_repair_reportid'];
}
}
else
{
  $already_exists[0]="nothing";
}
    $break='false';
    while($break=='false'){
      $rand=mt_rand(10000,999999);

      if(array_search($rand,$alredy_exists)===false){
          $break='stop';
      }else{

      }
    }

 echo "random number is : ".$echo;

你可以使用代码添加char,例如 - &gt; $rand=mt_rand(10000,999999) .$randomchar; // assume $radomchar contains char;

答案 9 :(得分:0)

您也可以考虑使用crypt() *在您的约束内生成[几乎保证]唯一ID。

答案 10 :(得分:0)

 <?php
    $hostname_conn = "localhost";
    $database_conn = "user_id";
    $username_conn = "root";
    $password_conn = "";
     $conn = mysql_pconnect($hostname_conn, $username_conn,   $password_conn) or trigger_error(mysql_error(),E_USER_ERROR); 
   mysql_select_db($database_conn,$conn);
   // run an endless loop      
    while(1) {       
    $randomNumber = rand(1, 999999);// generate unique random number               
    $query = "SELECT * FROM tbl_rand WHERE the_number='".mysql_real_escape_string ($randomNumber)."'";  // check if it exists in database   
    $res =mysql_query($query,$conn);       
    $rowCount = mysql_num_rows($res);
     // if not found in the db (it is unique), then insert the unique number into data_base and break out of the loop
    if($rowCount < 1) {
    $con = mysql_connect ("localhost","root");      
    mysql_select_db("user_id", $con);       
    $sql = "insert into tbl_rand(the_number) values('".$randomNumber."')";      
    mysql_query ($sql,$con);        
    mysql_close ($con);
    break;
    }   
}
  echo "inserted unique number into Data_base. use it as ID";
   ?>

答案 11 :(得分:0)

建议

crypt()并在一些配置文件中存储盐,从1开始盐,如果你发现重复移动到下一个值2.你可以使用2个字符,但这将为你提供足够的盐组合。 / p>

您可以从openssl_random_pseudo_bytes(8)生成字符串。因此,当使用crypt()运行时,这应该给出随机和短字符串(11个字符)。

从结果中删除盐,如果你在每次随机失败时改变盐,那么只有11个字符应该足够随机,超过100万。

答案 12 :(得分:0)

这会生成随机ID:

CREATE TABLE Persons (
    ID Integer PRIMARY KEY AUTOINCREMENT,
    LastName varchar(255) NOT NULL,
    FirstName varchar(255),
    Age int
);

答案 13 :(得分:0)

要获得唯一且外观随机的令牌,您可以仅加密主密钥,即:

SELECT HEX(AES_ENCRYPT(your_pk,'your_password')) AS 'token' FROM your_table;

这已经足够好,而且它具有可逆性,因此您不必将该令牌存储在表中,而只需生成即可。

另一个优点是,一旦您从该令牌中解码了PK,就不必对表进行大量的全文搜索,而只需简单而快速的PK搜索。

尽管有一个小问题。 MySql支持不同的block encryption modes,如果更改,{{3}}会完全改变您的令牌空间,从而使旧令牌无效...

要克服这一点,可以在生成令牌之前设置该变量,即:

SET block_encryption_mode = 'aes-256-cbc';

但是这有点浪费...解决方案是将加密模式使用的标记附加到令牌:

SELECT CONCAT(CONV(CRC32(@@GLOBAL.block_encryption_mode),10,35),'Z',HEX(AES_ENCRYPT(your_pk,'your_password'))) AS 'token' FROM your_table;

如果您希望将该令牌保留在INSERT的表中,则可能会出现另一个问题,因为要生成该令牌,您需要知道尚未插入的记录的primary_key ...当然,您可能只是{{ 1}},然后将INSERTUPDATE一起使用-但是,还有一个更好的解决方案:

LAST_INSERT_ID()

此解决方案的最后一个但并非最不重要的优点是,您可以轻松地以php,python,js或您可能使用的任何其他语言来复制它。

答案 14 :(得分:0)

您可以使用Twitter的雪花。

简而言之,它会根据时间,服务器ID和序列来生成唯一ID。它生成一个64位的值,因此它很小并且适合INT64。它还允许正确排序值。

https://developer.twitter.com/en/docs/basics/twitter-ids

总而言之,它允许多台服务器,高度并发,排序值以及所有这些都以64位显示。

这是MySQL的实现

https://github.com/EFTEC/snowflake-mysql

它由一个函数和一个表组成。

答案 15 :(得分:0)

使用它

    $info = random_bytes(16);
    $info[6] = chr(ord($info[6]) & 0x0f | 0x40); 
    $info[8] = chr(ord($info[8]) & 0x3f | 0x80); 
    $result =vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($info), 4));
    return $result;