當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]引入任何一種技術(shù)都是存在風(fēng)險(xiǎn)的,分庫(kù)分表當(dāng)然也不例外,除非庫(kù)、表數(shù)據(jù)量持續(xù)增加,大到一定程度,以至于現(xiàn)有高可用架構(gòu)已無(wú)法支撐,否則不建議大家做分庫(kù)分表,因?yàn)樽隽藬?shù)據(jù)分片后,你會(huì)發(fā)現(xiàn)自己踏上了一段踩坑之路,而分布式主鍵 ID 就是遇到的第一個(gè)坑。

引入任何一種技術(shù)都是存在風(fēng)險(xiǎn)的,分庫(kù)分表當(dāng)然也不例外,除非庫(kù)、表數(shù)據(jù)量持續(xù)增加,大到一定程度,以至于現(xiàn)有高可用架構(gòu)已無(wú)法支撐,否則不建議大家做分庫(kù)分表,因?yàn)樽隽藬?shù)據(jù)分片后,你會(huì)發(fā)現(xiàn)自己踏上了一段踩坑之路,而分布式主鍵 ID 就是遇到的第一個(gè)坑。

不同數(shù)據(jù)節(jié)點(diǎn)間生成全局唯一主鍵是個(gè)棘手的問(wèn)題,一張邏輯表 t_order 拆分成多個(gè)真實(shí)表 t_order_n,然后被分散到不同分片庫(kù) db_0、db_1... ,各真實(shí)表的自增鍵由于無(wú)法互相感知從而會(huì)產(chǎn)生重復(fù)主鍵,此時(shí)數(shù)據(jù)庫(kù)本身的自增主鍵,就無(wú)法滿(mǎn)足分庫(kù)分表對(duì)主鍵全局唯一的要求。

?db_0--
????|--?t_order_0
????|--?t_order_1
????|--?t_order_2
?db_1--
????|--?t_order_0
????|--?t_order_1
????|--?t_order_2

盡管我們可以通過(guò)嚴(yán)格約束,各個(gè)分片表自增主鍵的 初始值步長(zhǎng) 的方式來(lái)解決 ID 重復(fù)的問(wèn)題,但這樣會(huì)讓運(yùn)維成本陡增,而且可擴(kuò)展性極差,一旦要擴(kuò)容分片表數(shù)量,原表數(shù)據(jù)變動(dòng)比較大,所以這種方式不太可取。

?步長(zhǎng)?step?=?分表張數(shù)

?db_0--
????|--?t_order_0??ID:?0、6、12、18...
????|--?t_order_1??ID:?1、7、1319...
????|--?t_order_2??ID:?2、814、20...
?db_1--
????|--?t_order_0??ID:?39、15、21...
????|--?t_order_1??ID:?410、16、22...
????|--?t_order_2??ID:?511、1723...

目前已經(jīng)有了許多第三放解決方案可以完美解決這個(gè)問(wèn)題,比如基于 UUID、SNOWFLAKE算法 、segment號(hào)段,使用特定算法生成不重復(fù)鍵,或者直接引用主鍵生成服務(wù),像美團(tuán)(Leaf)和 滴滴(TinyId)等。

sharding-jdbc 內(nèi)置了兩種分布式主鍵生成方案,UUIDSNOWFLAKE,不僅如此它還抽離出分布式主鍵生成器的接口,以便于開(kāi)發(fā)者實(shí)現(xiàn)自定義的主鍵生成器,后續(xù)我們會(huì)在自定義的生成器中接入 滴滴(TinyId)的主鍵生成服務(wù)。

前邊介紹過(guò)在 sharding-jdbc 中要想為某個(gè)字段自動(dòng)生成主鍵 ID,只需要在 application.properties 文件中做如下配置:

#?主鍵字段
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
#?主鍵ID?生成方案
spring.shardingsphere.sharding.tables.t_order.key-generator.type=UUID
#?工作機(jī)器?id
spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=123

key-generator.column 表示主鍵字段,key-generator.type 為主鍵 ID 生成方案(內(nèi)置或自定義的),key-generator.props.worker.id 為機(jī)器ID,在主鍵生成方案設(shè)為 SNOWFLAKE 時(shí)機(jī)器ID 會(huì)參與位運(yùn)算。

在使用 sharding-jdbc 分布式主鍵時(shí)需要注意兩點(diǎn):

  • 一旦 insert 插入操作的實(shí)體對(duì)象中主鍵字段已經(jīng)賦值,那么即使配置了主鍵生成方案也會(huì)失效,最后SQL 執(zhí)行的數(shù)據(jù)會(huì)以賦的值為準(zhǔn)。
  • 不要給主鍵字段設(shè)置自增屬性,否則主鍵ID 會(huì)以默認(rèn)的 SNOWFLAKE 方式生成。比如:用 mybatis plus@TableId 注解給字段 order_id 設(shè)置了自增主鍵,那么此時(shí)配置哪種方案,總是按雪花算法生成。

下面我們從源碼上分析下 sharding-jdbc 內(nèi)置主鍵生成方案 UUIDSNOWFLAKE 是怎么實(shí)現(xiàn)的。

UUID

打開(kāi) UUID 類(lèi)型的主鍵生成實(shí)現(xiàn)類(lèi) UUIDShardingKeyGenerator 的源碼發(fā)現(xiàn),它的生成規(guī)則只有 UUID.randomUUID() 這么一行代碼,額~ 心中默默來(lái)了一句臥槽。

UUID 雖然可以做到全局唯一性,但還是不推薦使用它作為主鍵,因?yàn)槲覀兊膶?shí)際業(yè)務(wù)中不管是 user_id 還是 order_id 主鍵多為整型,而 UUID 生成的是個(gè) 32 位的字符串。

它的存儲(chǔ)以及查詢(xún)對(duì) MySQL 的性能消耗較大,而且 MySQL 官方也明確建議,主鍵要盡量越短越好,作為數(shù)據(jù)庫(kù)主鍵 UUID 的無(wú)序性還會(huì)導(dǎo)致數(shù)據(jù)位置頻繁變動(dòng),嚴(yán)重影響性能。

public?final?class?UUIDShardingKeyGenerator?implements?ShardingKeyGenerator?{
????private?Properties?properties?=?new?Properties();

????public?UUIDShardingKeyGenerator()?{
????}

????public?String?getType()?{
????????return?"UUID";
????}

????public?synchronized?Comparable?generateKey()?{
????????return?UUID.randomUUID().toString().replaceAll("-",?"");
????}

????public?Properties?getProperties()?{
????????return?this.properties;
????}

????public?void?setProperties(Properties?properties)?{
????????this.properties?=?properties;
????}
}

SNOWFLAKE

SNOWFLAKE(雪花算法)是默認(rèn)使用的主鍵生成方案,生成一個(gè) 64bit的長(zhǎng)整型(Long)數(shù)據(jù)。

sharding-jdbc 中雪花算法生成的主鍵主要由 4部分組成,1bit符號(hào)位、41bit時(shí)間戳位、10bit工作進(jìn)程位以及 12bit 序列號(hào)位。

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

符號(hào)位(1bit位)

Java 中 Long 型的最高位是符號(hào)位,正數(shù)是0,負(fù)數(shù)是1,一般生成ID都為正數(shù),所以默認(rèn)為0

時(shí)間戳位(41bit)

41位的時(shí)間戳可以容納的毫秒數(shù)是 2 的 41次冪,而一年的總毫秒數(shù)為 1000L * 60 * 60 * 24 * 365,計(jì)算使用時(shí)間大概是69年,額~,我有生之間算是夠用了。

Math.pow(2,?41)?/?(365?*?24?*?60?*?60?*?1000L)?=?=?69年?

工作進(jìn)程位(10bit)

表示一個(gè)唯一的工作進(jìn)程id,默認(rèn)值為 0,可通過(guò) key-generator.props.worker.id 屬性設(shè)置。

spring.shardingsphere.sharding.tables.t_order.key-generator.props.worker.id=0000

序列號(hào)位(12bit)

同一毫秒內(nèi)生成不同的ID。

時(shí)鐘回?fù)?/h3>

了解了雪花算法的主鍵 ID 組成后不難發(fā)現(xiàn),這是一種嚴(yán)重依賴(lài)于服務(wù)器時(shí)間的算法,而依賴(lài)服務(wù)器時(shí)間的就會(huì)遇到一個(gè)棘手的問(wèn)題:時(shí)鐘回?fù)?/code>。

為什么會(huì)出現(xiàn)時(shí)鐘回?fù)苣兀?/span>

互聯(lián)網(wǎng)中有一種網(wǎng)絡(luò)時(shí)間協(xié)議 ntp 全稱(chēng) (Network Time Protocol) ,專(zhuān)門(mén)用來(lái)同步、校準(zhǔn)網(wǎng)絡(luò)中各個(gè)計(jì)算機(jī)的時(shí)間。

這就是為什么,我們的手機(jī)現(xiàn)在不用手動(dòng)校對(duì)時(shí)間,可每個(gè)人的手機(jī)時(shí)間還都是一樣的。

我們的硬件時(shí)鐘可能會(huì)因?yàn)楦鞣N原因變得不準(zhǔn)( 快了慢了 ),此時(shí)就需要 ntp 服務(wù)來(lái)做時(shí)間校準(zhǔn),做校準(zhǔn)的時(shí)候就會(huì)發(fā)生服務(wù)器時(shí)鐘的 跳躍 或者 回?fù)?/code> 的問(wèn)題。

雪花算法如何解決時(shí)鐘回?fù)?/span>

服務(wù)器時(shí)鐘回?fù)軙?huì)導(dǎo)致產(chǎn)生重復(fù)的 ID,SNOWFLAKE 方案中對(duì)原有雪花算法做了改進(jìn),增加了一個(gè)最大容忍的時(shí)鐘回?fù)芎撩霐?shù)。

如果時(shí)鐘回?fù)艿臅r(shí)間超過(guò)最大容忍的毫秒數(shù)閾值,則程序直接報(bào)錯(cuò);如果在可容忍的范圍內(nèi),默認(rèn)分布式主鍵生成器,會(huì)等待時(shí)鐘同步到最后一次主鍵生成的時(shí)間后再繼續(xù)工作。

最大容忍的時(shí)鐘回?fù)芎撩霐?shù),默認(rèn)值為 0,可通過(guò)屬性 max.tolerate.time.difference.milliseconds 設(shè)置。

#?最大容忍的時(shí)鐘回?fù)芎撩霐?shù)
spring.shardingsphere.sharding.tables.t_order.key-generator.max.tolerate.time.difference.milliseconds=5

下面是看下它的源碼實(shí)現(xiàn)類(lèi) SnowflakeShardingKeyGenerator,核心流程大概如下:

最后一次生成主鍵的時(shí)間 lastMilliseconds 與 當(dāng)前時(shí)間currentMilliseconds 做比較,如果 lastMilliseconds > currentMilliseconds則意味著時(shí)鐘回調(diào)了。

那么接著判斷兩個(gè)時(shí)間的差值(timeDifferenceMilliseconds)是否在設(shè)置的最大容忍時(shí)間閾值 max.tolerate.time.difference.milliseconds內(nèi),在閾值內(nèi)則線(xiàn)程休眠差值時(shí)間 Thread.sleep(timeDifferenceMilliseconds),否則大于差值直接報(bào)異常。

?
/**
?*?@author?xiaofu
?*/

public?final?class?SnowflakeShardingKeyGenerator?implements?ShardingKeyGenerator{
????@Getter
????@Setter
????private?Properties?properties?=?new?Properties();
????
????public?String?getType()?{
????????return?"SNOWFLAKE";
????}
????
????public?synchronized?Comparable?generateKey()?{
?????/**
??????*?當(dāng)前系統(tǒng)時(shí)間毫秒數(shù)?
??????*/
?
????????long?currentMilliseconds?=?timeService.getCurrentMillis();
????????/**
?????????*?判斷是否需要等待容忍時(shí)間差,如果需要,則等待時(shí)間差過(guò)去,然后再獲取當(dāng)前系統(tǒng)時(shí)間?
?????????*/
?
????????if?(waitTolerateTimeDifferenceIfNeed(currentMilliseconds))?{
????????????currentMilliseconds?=?timeService.getCurrentMillis();
????????}
????????/**
?????????*?如果最后一次毫秒與?當(dāng)前系統(tǒng)時(shí)間毫秒相同,即還在同一毫秒內(nèi)?
?????????*/

????????if?(lastMilliseconds?==?currentMilliseconds)?{
?????????/**
??????????*?&位與運(yùn)算符:兩個(gè)數(shù)都轉(zhuǎn)為二進(jìn)制,如果相對(duì)應(yīng)位都是1,則結(jié)果為1,否則為0
??????????*?當(dāng)序列為4095時(shí),4095+1后的新序列與掩碼進(jìn)行位與運(yùn)算結(jié)果是0
??????????*?當(dāng)序列為其他值時(shí),位與運(yùn)算結(jié)果都不會(huì)是0
??????????*?即本毫秒的序列已經(jīng)用到最大值4096,此時(shí)要取下一個(gè)毫秒時(shí)間值
??????????*/

????????????if?(0L?==?(sequence?=?(sequence?+?1)?&?SEQUENCE_MASK))?{
????????????????currentMilliseconds?=?waitUntilNextTime(currentMilliseconds);
????????????}
????????}?else?{
?????????/**
??????????*?上一毫秒已經(jīng)過(guò)去,把序列值重置為1?
??????????*/

????????????vibrateSequenceOffset();
????????????sequence?=?sequenceOffset;
????????}
????????lastMilliseconds?=?currentMilliseconds;
????????
????????/**
?????????*?XX......XX?XX000000?00000000?00000000?時(shí)間差?XX
?????????*????XXXXXX?XXXX0000?00000000?機(jī)器ID?XX
?????????*???????????????XXXX?XXXXXXXX?序列號(hào)?XX
?????????*??三部分進(jìn)行|位或運(yùn)算:如果相對(duì)應(yīng)位都是0,則結(jié)果為0,否則為1
?????????*/

????????return?((currentMilliseconds?-?EPOCH)?<????}
????
????/**
?????*?判斷是否需要等待容忍時(shí)間差
?????*/

????@SneakyThrows
????private?boolean?waitTolerateTimeDifferenceIfNeed(final?long?currentMilliseconds)?{
?????/**
??????*?如果獲取ID時(shí)的最后一次時(shí)間毫秒數(shù)小于等于當(dāng)前系統(tǒng)時(shí)間毫秒數(shù),屬于正常情況,則不需要等待?
??????*/

????????if?(lastMilliseconds?<=?currentMilliseconds)?{
????????????return?false;
????????}
????????/**
?????????*?===>時(shí)鐘回?fù)艿那闆r(生成序列的時(shí)間大于當(dāng)前系統(tǒng)的時(shí)間),需要等待時(shí)間差?
?????????*/

????????/**
?????????*?獲取ID時(shí)的最后一次毫秒數(shù)減去當(dāng)前系統(tǒng)時(shí)間毫秒數(shù)的時(shí)間差?
?????????*/

????????long?timeDifferenceMilliseconds?=?lastMilliseconds?-?currentMilliseconds;
????????/**
?????????*?時(shí)間差小于最大容忍時(shí)間差,即當(dāng)前還在時(shí)鐘回?fù)艿臅r(shí)間差之內(nèi)?
?????????*/

????????Preconditions.checkState(timeDifferenceMilliseconds?????????????????"Clock?is?moving?backwards,?last?time?is?%d?milliseconds,?current?time?is?%d?milliseconds",?lastMilliseconds,?currentMilliseconds);
????????/**
?????????*?線(xiàn)程休眠時(shí)間差?
?????????*/

????????Thread.sleep(timeDifferenceMilliseconds);
????????return?true;
????}
????
????//?配置的機(jī)器ID
????private?long?getWorkerId()?{
????????long?result?=?Long.valueOf(properties.getProperty("worker.id",?String.valueOf(WORKER_ID)));
????????Preconditions.checkArgument(result?>=?0L?&&?result?????????return?result;
????}
????
????private?int?getMaxTolerateTimeDifferenceMilliseconds()?{
????????return?Integer.valueOf(properties.getProperty("max.tolerate.time.difference.milliseconds",?String.valueOf(MAX_TOLERATE_TIME_DIFFERENCE_MILLISECONDS)));
????}
????
????private?long?waitUntilNextTime(final?long?lastTime)?{
????????long?result?=?timeService.getCurrentMillis();
????????while?(result?<=?lastTime)?{
????????????result?=?timeService.getCurrentMillis();
????????}
????????return?result;
????}
}

但從 SNOWFLAKE 方案生成的主鍵ID 來(lái)看,order_id 它是一個(gè)18位的長(zhǎng)整型數(shù)字,是不是發(fā)現(xiàn)它太長(zhǎng)了,想要 MySQL 那種從 0 遞增的自增主鍵該怎么實(shí)現(xiàn)呢?別急,后邊已經(jīng)會(huì)給出了解決辦法!

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

自定義

sharding-jdbc 利用 SPI 全稱(chēng)( Service Provider Interface) 機(jī)制拓展主鍵生成規(guī)則,這是一種服務(wù)發(fā)現(xiàn)機(jī)制,通過(guò)掃描項(xiàng)目路徑 META-INF/services 下的文件,并自動(dòng)加載文件里所定義的類(lèi)。

實(shí)現(xiàn)自定義主鍵生成器其實(shí)比較簡(jiǎn)單,只有兩步。

第一步,實(shí)現(xiàn) ShardingKeyGenerator 接口,并重寫(xiě)其內(nèi)部方法,其中 getType() 方法為自定義的主鍵生產(chǎn)方案類(lèi)型、generateKey() 方法則是具體生成主鍵的規(guī)則。

下面代碼中用 AtomicInteger 來(lái)模擬實(shí)現(xiàn)一個(gè)有序自增的 ID 生成。

/**
?*?@Author:?xiaofu
?*?@Description:?自定義主鍵生成器
?*/

@Component
public?class?MyShardingKeyGenerator?implements?ShardingKeyGenerator?{


????private?final?AtomicInteger?count?=?new?AtomicInteger();

????/**
?????*?自定義的生成方案類(lèi)型
?????*/

????@Override
????public?String?getType()?{
????????return?"XXX";
????}

????/**
?????*?核心方法-生成主鍵ID
?????*/

????@Override
????public?Comparable?generateKey()?{
????????return?count.incrementAndGet();
????}

????@Override
????public?Properties?getProperties()?{
????????return?null;
????}

????@Override
????public?void?setProperties(Properties?properties)?{

????}
}

第二步,由于是利用 SPI 機(jī)制實(shí)現(xiàn)功能拓展,我們要在 META-INF/services 文件中配置自定義的主鍵生成器類(lèi)路勁。

com.xiaofu.sharding.key.MyShardingKeyGenerator
分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

上面這些弄完我們測(cè)試一下,配置定義好的主鍵生成類(lèi)型 XXX,并插入幾條數(shù)據(jù)看看效果。

spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=XXX

通過(guò)控制臺(tái)的SQL 解析日志發(fā)現(xiàn),order_id 字段已按照有序自增的方式插入記錄,說(shuō)明配置的沒(méi)問(wèn)題。

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

舉一反九

既然可以自定義生成方案,那么實(shí)現(xiàn)分布式主鍵的思路就很多了,又想到之前我寫(xiě)的這篇 《9種 分布式ID生成方案》,發(fā)現(xiàn)可以完美兼容,這里挑選其中的 滴滴(Tinyid)來(lái)實(shí)踐一下,由于它是個(gè)單獨(dú)的分布式ID生成服務(wù),所以要先搭建環(huán)境了。

Tinyid 的服務(wù)提供HttpTinyid-client 兩種接入方式,下邊使用 Tinyid-client 方式快速使用,更多的細(xì)節(jié)到這篇文章里看吧,實(shí)在是介紹過(guò)太多次了。

Tinyid 服務(wù)搭建

先拉源代碼 https://github.com/didi/tinyid.git

由于是基于號(hào)段模式實(shí)現(xiàn)的分布式ID,所以依賴(lài)于數(shù)據(jù)庫(kù),要?jiǎng)?chuàng)建相應(yīng)的表 tiny_id_info 、tiny_id_token 并插入默認(rèn)數(shù)據(jù)。


CREATE?TABLE?`tiny_id_info`?(
?`id`?BIGINT?(20)?UNSIGNED?NOT?NULL?AUTO_INCREMENT?COMMENT?'自增主鍵',
?`biz_type`?VARCHAR?(63)?NOT?NULL?DEFAULT?''?COMMENT?'業(yè)務(wù)類(lèi)型,唯一',
?`begin_id`?BIGINT?(20)?NOT?NULL?DEFAULT?'0'?COMMENT?'開(kāi)始id,僅記錄初始值,無(wú)其他含義。初始化時(shí)begin_id和max_id應(yīng)相同',
?`max_id`?BIGINT?(20)?NOT?NULL?DEFAULT?'0'?COMMENT?'當(dāng)前最大id',
?`step`?INT?(11)?DEFAULT?'0'?COMMENT?'步長(zhǎng)',
?`delta`?INT?(11)?NOT?NULL?DEFAULT?'1'?COMMENT?'每次id增量',
?`remainder`?INT?(11)?NOT?NULL?DEFAULT?'0'?COMMENT?'余數(shù)',
?`create_time`?TIMESTAMP?NOT?NULL?DEFAULT?'2010-01-01?00:00:00'?COMMENT?'創(chuàng)建時(shí)間',
?`update_time`?TIMESTAMP?NOT?NULL?DEFAULT?'2010-01-01?00:00:00'?COMMENT?'更新時(shí)間',
?`version`?BIGINT?(20)?NOT?NULL?DEFAULT?'0'?COMMENT?'版本號(hào)',
?PRIMARY?KEY?(`id`),
?UNIQUE?KEY?`uniq_biz_type`?(`biz_type`)
)?ENGINE?=?INNODB?AUTO_INCREMENT?=?1?DEFAULT?CHARSET?=?utf8?COMMENT?'id信息表';

CREATE?TABLE?`tiny_id_token`?(
?`id`?INT?(11)?UNSIGNED?NOT?NULL?AUTO_INCREMENT?COMMENT?'自增id',
?`token`?VARCHAR?(255)?NOT?NULL?DEFAULT?''?COMMENT?'token',
?`biz_type`?VARCHAR?(63)?NOT?NULL?DEFAULT?''?COMMENT?'此token可訪(fǎng)問(wèn)的業(yè)務(wù)類(lèi)型標(biāo)識(shí)',
?`remark`?VARCHAR?(255)?NOT?NULL?DEFAULT?''?COMMENT?'備注',
?`create_time`?TIMESTAMP?NOT?NULL?DEFAULT?'2010-01-01?00:00:00'?COMMENT?'創(chuàng)建時(shí)間',
?`update_time`?TIMESTAMP?NOT?NULL?DEFAULT?'2010-01-01?00:00:00'?COMMENT?'更新時(shí)間',
?PRIMARY?KEY?(`id`)
)?ENGINE?=?INNODB?AUTO_INCREMENT?=?1?DEFAULT?CHARSET?=?utf8?COMMENT?'token信息表';

INSERT?INTO?`tiny_id_token`?(`id`,?`token`,?`biz_type`,?`remark`,?`create_time`,?`update_time`)?VALUES?('1',?'0f673adf80504e2eaa552f5d791b644c',?'order',?'1',?'2017-12-14?16:36:46',?'2017-12-14?16:36:48');

INSERT?INTO?`tiny_id_info`?(`id`,?`biz_type`,?`begin_id`,?`max_id`,?`step`,?`delta`,?`remainder`,?`create_time`,?`update_time`,?`version`)?VALUES?('1',?'order',?'1',?'1',?'100000',?'1',?'0',?'2018-07-21?23:52:58',?'2018-07-22?23:19:27',?'1');

并在 Tinyid 服務(wù)中配置上邊表所在數(shù)據(jù)源信息

datasource.tinyid.primary.url=jdbc:mysql://47.93.6.e:3306/ds-0?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
datasource.tinyid.primary.username=root
datasource.tinyid.primary.password=root

最后項(xiàng)目 maven install ,右鍵 TinyIdServerApplication 啟動(dòng)服務(wù), Tinyid 分布式ID生成服務(wù)就搭建完畢了。

自定義 Tinyid 主鍵類(lèi)型

Tinyid 服務(wù)搭建完下邊在項(xiàng)目中引入它,新建個(gè) tinyid_client.properties 文件其中添加 tinyid.servertinyid.token 屬性,token 為之前 SQL 預(yù)先插入的用戶(hù)數(shù)據(jù)。

#?tinyid?分布式ID
#?服務(wù)地址
tinyid.server=127.0.0.1:9999
#?業(yè)務(wù)token
tinyid.token=0f673adf80504e2eaa552f5d791b644c

代碼中獲取 ID更簡(jiǎn)單,只需一行代碼,業(yè)務(wù)類(lèi)型 order 是之前 SQ L 預(yù)先插入的數(shù)據(jù)。

Long?id?=?TinyId.nextId("order");

我們開(kāi)始自定義 Tinyid ?主鍵生成類(lèi)型的實(shí)現(xiàn)類(lèi) TinyIdShardingKeyGenerator 。

/**
?*?@Author:?xiaofu
?*?@Description:?自定義主鍵生成器
?*/

@Component
public?class?TinyIdShardingKeyGenerator?implements?ShardingKeyGenerator?{
????
????/**
?????*?自定義的生成方案類(lèi)型
?????*/

????@Override
????public?String?getType()?{
????????return?"tinyid";
????}

????/**
?????*?核心方法-生成主鍵ID
?????*/

????@Override
????public?Comparable?generateKey()?{
????????
????????Long?id?=?TinyId.nextId("order");
????????
????????return?id;
????}

????@Override
????public?Properties?getProperties()?{
????????return?null;
????}

????@Override
????public?void?setProperties(Properties?properties)?{

????}
}

并在配置文件中啟用 Tinyid ?主鍵生成類(lèi)型,到此配置完畢,趕緊測(cè)試一下。

#?主鍵字段
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
#?主鍵ID?生成方案
spring.shardingsphere.sharding.tables.t_order.key-generator.type=tinyid

測(cè)試 Tinyid 主鍵

向數(shù)據(jù)庫(kù)插入訂單記錄測(cè)試發(fā)現(xiàn),主鍵ID字段 order_id 已經(jīng)為趨勢(shì)遞增的了, Tinyid ?服務(wù)成功接入,完美!

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

- END -

特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒(méi)關(guān)注的小伙伴,可以長(zhǎng)按關(guān)注一下:

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

長(zhǎng)按訂閱更多精彩▼

分庫(kù)分表的9種分布式主鍵ID生成方案,挺全乎的

如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話(huà)語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉