I was wo开发者_开发百科ndering if anybody knew a good way to create a unique random integer id for a primary key for a table. I'm using 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."
If security is your aim then using Base62, even with a "randomly" generated number won't help.
A better option would:
- Do not re-invent the wheel -- use
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"
If your're open to suggestions and you can implement it, use UUIDs.
MySQL's UUID()
function will return a 36 chars value which can be used for 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. This function needs to use random + check of existing ids to return one that is not used before.
Check RAND()
function for MySQL.
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!
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.
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.
For example I have an orders table with order_id in it. This id is generated on the fly when the user enters the order, incrementally 1,2,3 etc forever. The user does not need to see this internal id.
Then I have another table - unique_ids with (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. (If I ever get 10000 orders in one day I'll have a problem - but that would be a good problem to have!)
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
):
Short
- Generate random
number
foruser_id (UNIQUE)
- Insert row with generated
number
asuser_id
- If inserted row count equal to 0, go to point 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);
- All values (
$min
,$max
,0.5
) are just for explanation and they have no statistical meaning. - Functions
insert_to_table
andreport_this_fact
are not build in PHP. The are also as numbers just for clarify of explanation purposes.
You can use an AUTO_INCREMENT
for your table, but give the users the encrypted version:
encrypted_id: SELECT HEX(AES_ENCRYPT(id, 'my-private-key'));
id: SELECT AES_DECRYPT(UNHEX(encrypted_id), 'my-private-key');
my way, for both 32bit and 64bit platform. result is 64bit
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;
}
AUTO_INCREMENT
is going to be your best bet for this.
Here are some examples.
If you need to you can adjust where the increment value starts (by default it's 1).
There is an AUTO_INCREMENT
feature. I would use that.
See here more examples.
精彩评论