在現代軟件開發中,生成唯一ID是一個必須掌握的技能。每個對象都應該有一個唯一的標識符。而Java作為一門流行的面向對象編程語言,提供了很多方式來生成唯一ID。本文將從以下幾個方面探討Java生成唯一ID的技術及其應用:
一、UUID
UUID (通用唯一標識符) 是指在一台機器上生成的數字,它保證了一個標識符在全球範圍內的唯一性。UUID 由以下幾部分的組合:
- 當前日期和時間
- 時鐘序列
- 全局唯一的 IEEE 機器識別號(如果有網卡,從網卡 MAC 地址獲得,沒有則生成隨機的IEEE 機器識別號)
Java提供了UUID類來生成唯一ID。我們可以使用UUID類的randomUUID()靜態方法,如下所示:
import java.util.UUID; public class UUIDTest { public static void main(String[] args) { UUID uuid = UUID.randomUUID(); System.out.println(uuid.toString()); } }
該段代碼將會輸出一個類似於「c5be9692-1f54-4701-bf51-1736e10daa8c」的UUID字符串。UUID可以用於唯一標識本地文件、數據庫記錄甚至是整個系統實例。
二、Snowflake算法
Snowflake算法是Twitter開源的分佈式ID生成算法,採用了64位(2的64次方)長的唯一ID;它是將一個64位的二進制實數分成了五個部分,各自表示的位數如下:
- 1位標識,不用,為0
- 41位時間戳(毫秒級),注意,41位時間戳不是存儲當前時間的時間戳,而是存儲時間戳的差值(當前時間戳 – 開始時間戳) 的值,這樣可以使用41位的時間戳使ID從 1970年至少可以使用69年。
- 10位的數據機器位,可以部署在10個數據中心
- 12位的序列號,毫秒內的計數,同一機器,同一時間戳內產生的ID序號都是相同的。
Snowflake算法需要一個開始時間戳(一般是項目開始運行的時間),這個時間戳使用後不能更改,因為這個時間戳就是確定41位時間戳的初始值的。Java代碼實現如下:
public class SnowflakeIdWorker { private final long twepoch = 1288834974657L; private final long workerIdBits = 5L; private final long datacenterIdBits = 5L; private final long maxWorkerId = -1L ^ (-1L << workerIdBits); private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private final long sequenceBits = 12L; private final long workerIdShift = sequenceBits; private final long datacenterIdShift = sequenceBits + workerIdBits; private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final long sequenceMask = -1L ^ (-1L < maxWorkerId || workerId maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } protected long timeGen() { return System.currentTimeMillis(); } }
使用Snowflake算法,需要先初始化一個SnowflakeIdWorker對象,然後可以使用它的nextId()方法生成新的ID。例如:
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); long id = idWorker.nextId(); System.out.println(id);
該段代碼將會輸出一個唯一ID整數。
三、Redis生成唯一ID
除了生成唯一ID的Java代碼,我們還可以使用Redis實現唯一ID。Redis是一個流行的Key-Value存儲數據庫,除了對數據進行緩存,它也提供了很多不同的數據結構和功能。我們可以使用Redis的incr命令來生成唯一ID。
我們可以使用以下方法在Java中使用Redis生成唯一ID:
import redis.clients.jedis.Jedis; public class RedisTest { public static void main(String[] args) { Jedis jedis = new Jedis("localhost"); long id = jedis.incr("unique_id"); System.out.println(id); } }
該段代碼將會輸出一個唯一ID整數,它的值將比上一個唯一ID整數大1。
四、分佈式ID生成器
隨着分佈式計算和雲計算的盛行,單一節點的ID生成方式已經不能滿足現代應用的需求。分佈式ID生成器可以在多個節點和服務之間生成全局唯一的ID,例如Leaf-segment和Leaf-snowflake。我們可以使用這些生成器生成唯一ID,並將其用於分佈式系統架構中。
以Leaf-snowflake為例,在Java中使用方法如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class LeafSnowflakeService { @Autowired private SnowflakeService snowflakeService; public Long nextId() { return snowflakeService.nextId(); } }
Leaf-snowflake在內部使用了Snowflake算法來生成唯一ID,同時也考慮了分佈式部署等問題。通過上述代碼,我們可以在Spring應用中使用分佈式ID生成器生成唯一ID。
五、總結
本文從多個方面探討了Java生成唯一ID的方法及其應用。使用UUID、Snowflake算法、Redis和分佈式ID生成器,我們可以在Java中生成全局唯一的ID。在實際應用中,需要根據自己的需求和現有系統架構選擇合適的唯一ID生成方式。在分佈式應用系統中,使用分佈式ID生成器可以保證全局唯一性,並且可以讓開發者自由控制節點數和序列長度,是一種較為通用的解決方案。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/157787.html