在軟體系統中,唯一標識符是非常重要的。一個唯一標識符是一個用來標識一個實體或對象的字元串或數字。比如,我們的用戶ID、訂單號等都需要是唯一的。在本文中,我們將探討一些關於生成唯一標識符的最佳實踐。
一、UUID
UUID(通用唯一標識符)是一個用於標識信息的128位數字,它的唯一性和隨機性很高。它不需要像序列號那樣在多台計算機之間進行同步,也不需要像GUID那樣需要Windows API的支持。因此,它是一種生成唯一標識符的很好選擇。
<?php
function generateUUID() {
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
?>
這個generateUUID函數生成一個UUID。注意,它使用了mt_rand,這是一個更好的隨機數生成器。如果你在舊的PHP版本中使用rand,你可能會得到兩個完全相同的UUID。
二、Snowflake演算法
Snowflake是由Twitter發明的演算法,它可以在分散式系統中生成唯一的ID,是生成分散式唯一ID的一種解決方案。它的核心思想是將ID分解成多個部分,通過對每個部分的合理設計來保證生成的所有ID全局唯一。Snowflake IDs由以下幾個部分組成:
- 一個時間戳(毫秒級,41位)
- 一個機器ID(10位)
- 一個序列號(12位)
<?php
class Snowflake
{
const EPOCH = 1593649964177;
const MACHINE_ID = 1;
private static $lastTimestamp = -1;
private static $sequence = 0;
public static function generateId()
{
$timestamp = self::getUnixTimestampInMilliseconds();
if (self::$lastTimestamp === $timestamp) {
self::$sequence = (self::$sequence + 1) & 4095;
if (self::$sequence === 0) {
$timestamp = self::waitNextMillis($timestamp);
}
} else {
self::$sequence = 0;
}
$lastTimestamp = $timestamp;
return ((string) ($timestamp - self::EPOCH) << 22)
| ((string) (self::MACHINE_ID << 12))
| (string) self::$sequence;
}
private static function getUnixTimestampInMilliseconds()
{
return round(microtime(true) * 1000);
}
private static function waitNextMillis($timestamp)
{
while ($timestamp === self::$lastTimestamp) {
$timestamp = self::getUnixTimestampInMilliseconds();
}
return $timestamp;
}
}
?>
如上述代碼,我們可以用Snowflake生成全局唯一標識符,可以調用Snowflake::generateId()函數來生成唯一 ID。
三、利用資料庫
使用資料庫自增長列的思路是最傳統的方式生成QQ號、訂單號等唯一編碼,利用auto_increment列可以生成唯一ID。然而,使用資料庫有一個明顯的缺點,那就是需要和資料庫進行交互,如果高並發,可能會佔用資料庫大量的資源。
<?php
class MysqlIdMaker
{
private $db;
public function __construct(mysqli $db)
{
$this->db = $db;
}
public function nextId()
{
$result = $this->db->query('SELECT next_id FROM sequence WHERE `key`=\'global\'');
if (!$result || $result->num_rows fetch_assoc();
$nextId = $row['next_id'];
$this->db->query(
'UPDATE sequence SET next_id=next_id+1 WHERE `key`=\'global\' AND next_id=' . $nextId
);
if ($this->db->affected_rows nextId();
}
return $nextId;
}
}
?>
上述例子中抽象出了一個MysqlIdMaker類,通過資料庫自增長列生成全局唯一ID,我們可以調用MysqlIdMaker::nextId()函數來生成下一個唯一ID。
四、結語
本文討論了生成唯一標識符的最佳實踐,包括使用UUID、Snowflake演算法和使用資料庫。不同的場景和需求,會有不同的選擇。我們可以根據具體的場景和需求,選擇合適的方法來生成唯一標識符。
原創文章,作者:FIGF,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/144212.html