您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“數(shù)據(jù)庫如何使用數(shù)據(jù)生成Sequence”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“數(shù)據(jù)庫如何使用數(shù)據(jù)生成Sequence”吧!
twitter 開源的分布式 id 生成算法,使用64 位的 long 型的 id。
41 bit,時間戳,單位為毫秒,2^41 - 1 換算成年可以表示69年的時間
10 bit,其中5個表示機(jī)房,5個表示機(jī)器ID
12 bit,錄同一個毫秒內(nèi)產(chǎn)生的不同 id,2^12 - 1 = 4096,可以表示同一個毫秒內(nèi)的 4096 個不同的 id
支持每秒幾萬并發(fā)
public class UniqueOrderGenerate {// ==============================Fields===========================================/** 開始時間截 (2018-07-03) */private final long twepoch = 1530607760000L;/** 機(jī)器id所占的位數(shù) */private final long workerIdBits = 5L;/** 數(shù)據(jù)標(biāo)識id所占的位數(shù) */private final long datacenterIdBits = 5L;/** 支持的最大機(jī)器id,結(jié)果是31 (這個移位算法可以很快的計(jì)算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù)) */private final long maxWorkerId = -1L ^ (-1L << workerIdBits);/** 支持的最大數(shù)據(jù)標(biāo)識id,結(jié)果是31 */private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);/** 序列在id中占的位數(shù) */private final long sequenceBits = 12L;/** 機(jī)器ID向左移12位 */private final long workerIdShift = sequenceBits;/** 數(shù)據(jù)標(biāo)識id向左移17位(12+5) */private final long datacenterIdShift = sequenceBits + workerIdBits;/** 時間截向左移22位(5+5+12) */private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;/** 生成序列的掩碼,這里為4095 (0b111111111111=0xfff=4095) */private final long sequenceMask = -1L ^ (-1L << sequenceBits);/** 工作機(jī)器ID(0~31) */private long workerId;/** 數(shù)據(jù)中心ID(0~31) */private long datacenterId;/** 毫秒內(nèi)序列(0~4095) */private long sequence = 0L;/** 上次生成ID的時間截 */private long lastTimestamp = -1L;//==============================Constructors=====================================/** * 構(gòu)造函數(shù) * @param workerId 工作ID (0~31) * @param datacenterId 數(shù)據(jù)中心ID (0~31) */public UniqueOrderGenerate(long workerId, long datacenterId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));}if (datacenterId > 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;}// ==============================Methods==========================================/** * 獲得下一個ID (該方法是線程安全的) * @return SnowflakeId */public synchronized long nextId() {long timestamp = timeGen();//如果當(dāng)前時間小于上一次ID生成的時間戳,說明系統(tǒng)時鐘回退過這個時候應(yīng)當(dāng)拋出異常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}//如果是同一時間生成的,則進(jìn)行毫秒內(nèi)序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;//毫秒內(nèi)序列溢出if (sequence == 0) {//阻塞到下一個毫秒,獲得新的時間戳timestamp = tilNextMillis(lastTimestamp);}}//時間戳改變,毫秒內(nèi)序列重置else {sequence = 0L;}//上次生成ID的時間截lastTimestamp = timestamp;//移位并通過或運(yùn)算拼到一起組成64位的IDreturn (((timestamp - twepoch) << timestampLeftShift) //| (datacenterId << datacenterIdShift) //| (workerId << workerIdShift) //| sequence);}/** * 阻塞到下一個毫秒,直到獲得新的時間戳 * @param lastTimestamp 上次生成ID的時間截 * @return 當(dāng)前時間戳 */protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}/** * 返回以毫秒為單位的當(dāng)前時間 * @return 當(dāng)前時間(毫秒) */protected long timeGen() {return System.currentTimeMillis();}//==============================Test=============================================/** 測試 */public static void main(String[] args) {UniqueOrderGenerate idWorker = new UniqueOrderGenerate(0, 0);for (int i = 0; i < 1000; i++) {long id = idWorker.nextId();//System.out.println(Long.toBinaryString(id));System.out.println(id);}}}
在數(shù)據(jù)庫中維護(hù)一張表
CREATE TABLE `sequence` ( `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `unique_id` bigint(18) DEFAULT NULL COMMENT 'unique_id', `UPDATED_TIME` timestamp NOT NULL COMMENT '更新時間', PRIMARY KEY (`ID`))
初始化:
設(shè)置步長step=5000, min = 0, max = 5000
截取時間字符串到當(dāng)天,curTime = ‘20190520’
和步長拼接,uniqueId = curTime + step = 201905201000
主要思路:
每臺應(yīng)用服務(wù)器預(yù)先取步長,存在JVM內(nèi)存中,nextKey++,步長用盡,更新數(shù)據(jù)庫。
數(shù)據(jù)庫建表,保存uniqueId,updateTime
設(shè)置數(shù)據(jù)庫更新步長,每次到達(dá)步長更新數(shù)據(jù)庫
根據(jù)業(yè)務(wù)量設(shè)置uniqueId長度,可以使用bigInt
時間加步長拼接作為唯一id
偽代碼
取步長 getUniqueueId() {if nextKey > max || curTime == null operaDb() nextKey++ seq = curTime + step}操作數(shù)據(jù)庫 operatDb() {查詢db當(dāng)前uniqueId 當(dāng)前uniqueId + step}
到此,相信大家對“數(shù)據(jù)庫如何使用數(shù)據(jù)生成Sequence”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。