简体   繁体   English

如何为表的主键创建唯一的随机整数ID?

[英]How to to create unique random integer ID for primary key for table?

I was wondering if anybody knew a good way to create a unique random integer id for a primary key for a table. 我想知道是否有人知道为表的主键创建唯一的随机整数id的好方法。 I'm using MySQL. 我正在使用MySQL。 The value has to be integer. 该值必须是整数。

In response to: "Because I want to use that value to Encode to Base62 and then use that for an id in a url. If i auto increment, it might be obvious to the user how the url id is generated." 回应: “因为我想使用该值来编码到Base62,然后将其用于url中的id。如果我自动递增,则用户可能会明白如何生成url id。”

If security is your aim then using Base62, even with a "randomly" generated number won't help. 如果安全是您的目标,那么使用Base62,即使使用“随机”生成的数字也无济于事。

A better option would: 更好的选择是:

  • Do not re-invent the wheel -- use AUTO_INCREMENT 不要重新发明轮子 - 使用AUTO_INCREMENT
  • Then use a cryptographic hash function + a randomly generated string (hidden in the db for that particular url) to generate the final "unique id for that url" 然后使用加密哈希函数+随机生成的字符串(隐藏在该特定URL的数据库中)以生成该URL的最终“唯一ID”

If your're open to suggestions and you can implement it, use UUIDs. 如果您愿意接受建议并且可以实施,请使用UUID。 MySQL's UUID() function will return a 36 chars value which can be used for ID . MySQL的UUID()函数将返回36个字符值,可用于ID

If you want to use integer, still, I think you need to create a function getRandID() that you will use in the INSERT statement. 如果你想使用整数,我认为你需要创建一个你将在INSERT语句中使用的函数getRandID() This function needs to use random + check of existing ids to return one that is not used before. 此函数需要使用现有ID的随机+检查来返回之前未使用的ID。

Check RAND() function for MySQL. 检查MySQL的RAND()函数。

How you generate the unique_ids is a useful question - but you seem to be making a counter productive assumption about when you generate them! 如何生成unique_ids是一个有用的问题 - 但是你似乎生成它们的时候做了一个反效果的假设!

My point is that you do not need to generate these unique id's at the time of creating your rows, because they are essentially independent of the data being inserted. 我的观点是,您在创建行时不需要生成这些唯一ID,因为它们基本上与所插入的数据无关。

What I do is pre-generate unique id's for future use, that way I can take my own sweet time and absolutely guarantee they are unique, and there's no processing to be done at the time of the insert. 我所做的是预先生成独特的id以供将来使用,这样我就可以享受自己的甜蜜时光并绝对保证它们是独一无二的,并且在插入时无需进行任何处理。

For example I have an orders table with order_id in it. 例如,我有一个order_id的订单表。 This id is generated on the fly when the user enters the order, incrementally 1,2,3 etc forever. 当用户输入订单时,会立即生成此ID,永久递增1,2,3等。 The user does not need to see this internal id. 用户无需查看此内部标识。

Then I have another table - unique_ids with (order_id, unique_id). 然后我有另一个表 - unique_ids与(order_id,unique_id)。 I have a routine that runs every night which pre-loads this table with enough unique_id rows to more than cover the orders that might be inserted in the next 24 hours. 我有一个每天晚上运行的例程,它会为此表预加载足够多的unique_id行,以覆盖可能在接下来的24小时内插入的订单。 (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!) (如果我在一天内获得10000个订单,我就会遇到问题 - 但这将是一个很好的问题!)

This approach guarantees uniqueness and takes any processing load away from the insert transaction and into the batch routine, where it does not affect the user. 这种方法保证了唯一性,并且可以将任何处理负载从插入事务转移到批处理例程中,而不会影响用户。

How about this approach ( PHP and MySQL ): 这种方法( PHPMySQL )怎么样:


Short

  1. Generate random number for user_id (UNIQUE) user_id (UNIQUE)生成随机number user_id (UNIQUE)
  2. Insert row with generated number as user_id 将生成的number作为user_id插入行
  3. If inserted row count equal to 0, go to point 1 如果插入的行数等于0,则转到第1点

Looks heavy? 看起来很重? Continue to read. 继续阅读。


Long :

Table: 表:

users (user_id int UNIQUE)

Code: 码:

<?php
// values stored in configuration
$min = 1;
$max = 1000000;

$numberOfLoops = 0;
do {
    $randomNumber = rand($min, $max);

    // the very insert
    $insertedRows = insert_to_table(
        'INSERT INTO foo_table (user_id) VALUES (:number)', 
        array(
            ':number' => $randomNumber
        ));

    $numberOfLoops++;

    // the magic
    if (!isset($reported) && $numberOfLoops / 10 > 0.5) {
        /**
         * We can assume that at least 50% of numbers
         * are already in use, so increment values of
         * $min and $max in configuration.
         */
        report_this_fact();
        $reported = true;
} while ($insertedRows < 1);

  1. All values ( $min , $max , 0.5 ) are just for explanation and they have no statistical meaning. 所有值( $min$max0.5 )仅用于解释,它们没有统计意义。
  2. Functions insert_to_table and report_this_fact are not build in PHP. 函数insert_to_tablereport_this_fact不是用PHP构建的。 The are also as numbers just for clarify of explanation purposes. 这些数字也只是为了澄清解释目的。

my way, for both 32bit and 64bit platform. 我的方式,适用于32位和64位平台。 result is 64bit 结果是64位

function hexstr2decstr($hexstr){
    $bigint = gmp_init($hexstr, 16);
    $bigint_string = gmp_strval($bigint);
    return $bigint_string;
}

function generate_64bitid(){
    return substr(md5(uniqid(rand(), true)), 16, 16);
}

function dbGetUniqueXXXId(){
    for($i = 0; $i < 10; $i++){
        $decstr = hexstr2decstr(generate_64bitid());

        //check duplicate for mysql.tablexxx
        if($dup == false){
            return $decstr;
        }
    }
    return false;
}

There is an AUTO_INCREMENT feature. 有一个AUTO_INCREMENT功能。 I would use that. 我会用那个。

See here more examples. 在这里看到更多例子。

AUTO_INCREMENT is going to be your best bet for this. AUTO_INCREMENT将是您最好的选择。

Here are some examples. 是一些例子。

If you need to you can adjust where the increment value starts (by default it's 1). 如果需要,您可以调整增量值开始的位置(默认情况下为1)。

You can use an AUTO_INCREMENT for your table, but give the users the encrypted version: 您可以为表使用AUTO_INCREMENT ,但为用户提供加密版本:

encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key')); encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key'));

id: SELECT AES_DECRYPT(UNHEX(encrypted_id), 'my-private-key'); id: SELECT AES_DECRYPT(UNHEX(encrypted_id), 'my-private-key');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM