PHP - Is uniqid("") a good practical solution to generate a unique and sequential key server side?
All,
I want to generate server side a user id during registration. This id should be sequential to allow for clustered indexing. It also needs to be unique, obviously.
To what extent can I use uniqid("")
for this? I am not building Google, and I assume that the risk of 2 users registering at the same microsecond is close to nill - but I have no practical experience on which to base myself. SQL will reject duplicate id's, and I can have a loop in my php code that will keep on sending new registration entries in case of collisions / data entry failures, but that's only a good approach if collisions are rare.
Alternatively, I could add a random postcript with uniqid("",TRUE)
, but then if 2 users register during the same microsecond, the keys can not be 开发者_StackOverflow社区sequential anymore.
What is the best, practical approach to my conundrum? Am I overthinking this?
Thanks,
JDelage
uniqid
is nothing more than an interface to microtime
(which is why it generates sequential IDs), and as such, it could be predictable and could create a duplicate.
This id should be sequential to allow for clustered indexing. It also needs to be unique, obviously. [...] Am I overthinking this?
Most databases, including MySQL, include transaction-safe sequence generators. MySQL's implementation, AUTO_INCREMENT
, is pretty darn primitive, but also effective. An auto-inc primary key would ensure uniqueness and is, more importantly, not weird.
That said, just ensuring that the id column in the table is a primary key is complete defense against duplicate IDs.
In database theory it is assumed that no events happen at the same time quantum, in your case microseconds. Many database concepts built on this presumption.
I didn't hear uniqid
generated same hashes on sequential requests. Because, its seed is microseconds and most probably your processor executes a machine instruction more or less in a microsecond, there is too much time between processing of two requests (even they are running concurrently in single CPU).
If you think that you may have collisions in 512-bit hash (32 hex characters), then you can build your own digest function which utilizes more characters from the alphabet and punctuations, because as I said before, we solved the time seed issue, all you should worry about must be to fully utilize seed and lower probability of collision.
If you want to be sure, you can serve requests in a mutually exclusive way and then after you serve for a request, you can insert a row to database (let's say a user registration, you insert a user record to the users table) and use PHP function mysql_insert_id()
then you can proceed to serving other request so that you can use recently inserted record id as a seed (which will be always different for any two consecutive requests).
Clarification about last paragraph upon request:
as I said before nothing happens at the same time in the databases, according to serving theory. Always, one of them served first. Therefore you can start a transaction in database. Let's say you are registering a new user. You'll say INSERT INTO users (username, password) VALUES (?, ?)
. There you go, you have inserted a new user. While this database query happens, you should implement a Mutual Exclusion Lock (mutex
), I don't know how it is done in PHP. If you implement a mutex, second request will wait until you finish your processing with first request. After the row is inserted on database, you use $i = mysql_insert_id()
to retrieve ID of just inserted row! When you say $i+1
for the ID of second user, it will be unique. Because first user was let's say 300
, then the second user will be 301
.
In fact, database auto increment IDs are always unique. If you want to have a unique string hash for the user, here's a method.
- Insert user. (query stated above)
- Get user's id with
$i = mysql_insert_id()
- Then encrypt this id with some digest algorithm such as
$d = strrev(md5($i))
- Then put this value on
unique_id
column ofusers
table with anUPDATE user SET unique_id='$d' where id=$i
query. - There you go, you have unique string for everyone.
I'm partial to UUID. It's not an incrementing number and should always be unqiue. However, do not use the function UUID in an INSERT statement. It can lead to problems.
精彩评论