欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MybatisPlus使用idworker解決雪花算法重復(fù)

 更新時(shí)間:2023年02月05日 10:07:31   作者:Winner002  
本文主要介紹了MybatisPlus使用idworker解決雪花算法重復(fù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、雪花算法datacenterId重復(fù)問題

華為云的服務(wù)器的/etc/hosts中都會(huì)生成一條 127.0.1.1 hostname的記錄 ,導(dǎo)致獲取network為null ,datacenterId 會(huì)取默認(rèn)值1,導(dǎo)致重復(fù)概率大大增加。

二、idworker 是一個(gè)基于zookeeper和snowflake算法的分布式統(tǒng)一ID生成工具

通過zookeeper自動(dòng)注冊(cè)機(jī)器(最多1024臺(tái)),無需手動(dòng)指定workerId和dataCenterId。
通過ZooKeeper持久順序節(jié)點(diǎn)特性,來配置維護(hù)節(jié)點(diǎn)的編號(hào)NODEID。
集群節(jié)點(diǎn)命名服務(wù)的基本流程是:
(1)啟動(dòng)節(jié)點(diǎn)服務(wù),連接ZooKeeper, 檢查命名服務(wù)根節(jié)點(diǎn)根節(jié)點(diǎn)是否存在,如果不存在就創(chuàng)建系統(tǒng)根節(jié)點(diǎn)。
(2)在根節(jié)點(diǎn)下創(chuàng)建一個(gè)臨時(shí)順序節(jié)點(diǎn),取回順序號(hào)做節(jié)點(diǎn)的NODEID。如何臨時(shí)節(jié)點(diǎn)太多,可以根據(jù)需要,刪除臨時(shí)節(jié)點(diǎn)。

由于是采用zookeeper順序節(jié)點(diǎn)的特性生成datacenterId和workerId,可以天然的保證datacenterId和workerId的唯一性,減少了人工維護(hù)的弊端。

三、idworker使用

1、mybatis-plus-boot-starter要升級(jí)到3.4.0以上,根據(jù)具體項(xiàng)目不同選擇合適的版本

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>

2、增加idworker的1.5.0版本的依賴

<dependency>
    <groupId>com.imadcn.framework</groupId>
    <artifactId>idworker</artifactId>
    <version>1.5.0</version>
</dependency>

3、增加IdAutoConfig.java文件

@Configurationd
public class IdAutoConfig {
? ? @Value("${mybatis-plus.zookeeper.serverLists:127.0.0.1:2181}")
? ? private String zkServerLists;

? ? @Bean
? ? public IdentifierGenerator idGenerator() {
? ? ? ? return new ImadcnIdentifierGenerator(zkServerLists);
? ? }
}

或者:

@Configuration
@MapperScan(
? ? ? ? basePackages = "com.script.idworker.mapper",
? ? ? ? sqlSessionFactoryRef = "sqlSessionFactory")
public class DataSourceConfig {
? ? @Value("${mybatis-plus.zookeeper.serverLists}")
? ? private String zkServerLists;

? ? @Bean(name = "dataSource")
? ? @Primary
? ? @ConfigurationProperties(prefix = "spring.datasource.druid")
? ? public DataSource getDataSource() {
? ? ? ? return DruidDataSourceBuilder.create().build();
? ? }

? ? @Bean(name = "sqlSessionFactory")
? ? @Primary
? ? public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource datasource) throws Exception {
? ? ? ? MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
? ? ? ? sqlSessionFactory.setDataSource(datasource);
? ? ? ? MybatisConfiguration configuration = new MybatisConfiguration();
? ? ? ? // 駝峰轉(zhuǎn)下劃線
? ? ? ? configuration.setMapUnderscoreToCamelCase(true);
? ? ? ? sqlSessionFactory.setConfiguration(configuration);
? ? ? ??
? ? ? ? // 設(shè)置使用Mybatis的Snowflake算法生成id
? ? ? ? GlobalConfig globalConfig = new GlobalConfig();
? ? ? ? globalConfig.setIdentifierGenerator(new ImadcnIdentifierGenerator(zkServerLists));
? ? ? ? sqlSessionFactory.setGlobalConfig(globalConfig);
? ? ? ??
? ? ? ? return sqlSessionFactory.getObject();
? ? }
}

4、可能curator版本沖突問題,idworker依賴的curator是4.x版本的,可能和dubbo依賴的curator版本沖突,可能和zookeeper 3.4.x版本不兼容

四、idworker源碼分析

1、返回SnowflakeId

Snowflake.java#nextId()

public synchronized long nextId() {
? ? long timestamp = timeGen();
? ? // 如果上一個(gè)timestamp與新產(chǎn)生的相等,則sequence加一(0-4095循環(huán));
? ? if (lastTimestamp == timestamp) {
? ? ? ? // 對(duì)新的timestamp,sequence從0開始
? ? ? ? sequence = sequence + 1 & sequenceMask;
? ? ? ? // 毫秒內(nèi)序列溢出
? ? ? ? if (sequence == 0) {
? ? ? ? ? ? // 阻塞到下一個(gè)毫秒,獲得新的時(shí)間戳
? ? ? ? ? ? sequence = RANDOM.nextInt(100);
? ? ? ? ? ? timestamp = tilNextMillis(lastTimestamp);
? ? ? ? }
? ? } else {
? ? ? ? // 時(shí)間戳改變,毫秒內(nèi)序列重置
? ? ? ? sequence = RANDOM.nextInt(100);
? ? }
? ? // 如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說明系統(tǒng)時(shí)鐘回退過這個(gè)時(shí)候應(yīng)當(dāng)拋出異常
? ? if (timestamp < lastTimestamp) {
? ? ? ? String message = String.format("Clock moved backwards. Refusing to generate id for %d milliseconds.",
? ? ? ? ? ? ? ? (lastTimestamp - timestamp));
? ? ? ? logger.error(message);
? ? ? ? throw new RuntimeException(message);
? ? }
? ? lastTimestamp = timestamp;
? ? // 移位并通過或運(yùn)算拼到一起組成64位的ID
? ? // 1 + 41 + 10 + 22
? ? // 0 - 0000000000 0000000000 0000000000 0000000000 0 - 0000000000 - 000000000000
? ? return timestamp - epoch << timestampLeftShift | workerId << workerIdShift | sequence;
}
  • 1位標(biāo)識(shí),由于long基本類型在Java中是帶符號(hào)的,最高位是符號(hào)位,正數(shù)是0,負(fù)數(shù)是1,所以id一般是正數(shù),最高位是0
  • 41位時(shí)間戳(毫秒級(jí)),注意,41位時(shí)間戳不是存儲(chǔ)當(dāng)前時(shí)間的時(shí)間戳,而是存儲(chǔ)時(shí)間戳的差值(當(dāng)前時(shí)間戳 - 開始時(shí)間戳)得到的值),這里的的開始時(shí)間戳,一般是我們的id生成器開始使用的時(shí)間,由我們程序來指定的(如下下面程序epoch屬性)。41位的時(shí)間戳,可以使用69年
  • 10位的數(shù)據(jù)機(jī)器位,可以部署在1024個(gè)節(jié)點(diǎn),包括5位datacenterId和5位workerId,
  • 12位序列,毫秒內(nèi)的計(jì)數(shù),12位的計(jì)數(shù)順序號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒(同一機(jī)器,同一時(shí)間戳)產(chǎn)生4096個(gè)ID序號(hào)
  • 加起來剛好64位,為一個(gè)Long型。

2、向zookeeper注冊(cè)workerId,返回workerId

ZookeeperWorkerRegister#register()

public long register() {
? ? InterProcessMutex lock = null;
? ? try {
? ? ? ? CuratorFramework client = (CuratorFramework) regCenter.getRawClient();
? ? ? ? lock = new InterProcessMutex(client, nodePath.getGroupPath());
? ? ? ? int numOfChildren = regCenter.getNumChildren(nodePath.getWorkerPath());
? ? ? ? if (numOfChildren < MAX_WORKER_NUM) {
? ? ? ? ? ? if (!lock.acquire(MAX_LOCK_WAIT_TIME_MS, TimeUnit.MILLISECONDS)) {
? ? ? ? ? ? ? ? String message = String.format("acquire lock failed after %s ms.", MAX_LOCK_WAIT_TIME_MS);
? ? ? ? ? ? ? ? throw new TimeoutException(message);
? ? ? ? ? ? }
? ? ? ? ? ? NodeInfo localNodeInfo = getLocalNodeInfo();
? ? ? ? ? ? List<String> children = regCenter.getChildrenKeys(nodePath.getWorkerPath());
? ? ? ? ? ? // 有本地緩存的節(jié)點(diǎn)信息,同時(shí)ZK也有這條數(shù)據(jù)
? ? ? ? ? ? if (localNodeInfo != null && children.contains(String.valueOf(localNodeInfo.getWorkerId()))) {
? ? ? ? ? ? ? ? String key = getNodePathKey(nodePath, localNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? String zkNodeInfoJson = regCenter.get(key);
? ? ? ? ? ? ? ? NodeInfo zkNodeInfo = createNodeInfoFromJsonStr(zkNodeInfoJson);
? ? ? ? ? ? ? ? if (checkNodeInfo(localNodeInfo, zkNodeInfo)) {
? ? ? ? ? ? ? ? ? ? // 更新ZK節(jié)點(diǎn)信息,保存本地緩存,開啟定時(shí)上報(bào)任務(wù)
? ? ? ? ? ? ? ? ? ? nodePath.setWorkerId(zkNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? ? ? zkNodeInfo.setUpdateTime(new Date());
? ? ? ? ? ? ? ? ? ? updateZookeeperNodeInfo(key, zkNodeInfo);
? ? ? ? ? ? ? ? ? ? saveLocalNodeInfo(zkNodeInfo);
? ? ? ? ? ? ? ? ? ? executeUploadNodeInfoTask(key, zkNodeInfo);
? ? ? ? ? ? ? ? ? ? return zkNodeInfo.getWorkerId();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? // 無本地信息或者緩存數(shù)據(jù)不匹配,開始向ZK申請(qǐng)節(jié)點(diǎn)機(jī)器ID
? ? ? ? ? ? for (int workerId = 0; workerId < MAX_WORKER_NUM; workerId++) {
? ? ? ? ? ? ? ? String workerIdStr = String.valueOf(workerId);
? ? ? ? ? ? ? ? if (!children.contains(workerIdStr)) { // 申請(qǐng)成功
? ? ? ? ? ? ? ? ? ? NodeInfo applyNodeInfo = createNodeInfo(nodePath.getGroupName(), workerId);
? ? ? ? ? ? ? ? ? ? nodePath.setWorkerId(applyNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? ? ? // 保存ZK節(jié)點(diǎn)信息,保存本地緩存,開啟定時(shí)上報(bào)任務(wù)
? ? ? ? ? ? ? ? ? ? saveZookeeperNodeInfo(nodePath.getWorkerIdPath(), applyNodeInfo);
? ? ? ? ? ? ? ? ? ? saveLocalNodeInfo(applyNodeInfo);
? ? ? ? ? ? ? ? ? ? executeUploadNodeInfoTask(nodePath.getWorkerIdPath(), applyNodeInfo);
? ? ? ? ? ? ? ? ? ? return applyNodeInfo.getWorkerId();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? throw new RegException("max worker num reached. register failed");
? ? } catch (RegException e) {
? ? ? ? throw e;
? ? } catch (Exception e) {
? ? ? ? logger.error("", e);
? ? ? ? throw new IllegalStateException(e.getMessage(), e);
? ? } finally {
? ? ? ? try {
? ? ? ? ? ? if (lock != null) {
? ? ? ? ? ? ? ? lock.release();
? ? ? ? ? ? }
? ? ? ? } catch (Exception ignored) {
? ? ? ? ? ? logger.error("", ignored);
? ? ? ? }
? ? }
}

五、idworker缺點(diǎn)

idworker向zookeeper注冊(cè)workerId,返回workerId后,會(huì)在本地緩存workerId,這樣就會(huì)導(dǎo)致如果同一臺(tái)機(jī)器部署了多個(gè)應(yīng)用,那么多個(gè)應(yīng)用會(huì)共享同一個(gè)本地緩存,所以仍有可能造成id重復(fù)。

到此這篇關(guān)于MybatisPlus使用idworker解決雪花算法重復(fù)的文章就介紹到這了,更多相關(guān)MybatisPlus dworker雪花算法重復(fù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM 堆和棧的區(qū)別

    JVM 堆和棧的區(qū)別

    本文主要介紹了JVM堆和棧的區(qū)別。具有很好的參考價(jià)值,下面跟著小編一起來看下吧
    2017-02-02
  • async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法詳解

    async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法詳解

    這篇文章主要介紹了async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • Java請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向區(qū)別詳解

    Java請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向區(qū)別詳解

    這篇文章主要介紹了Java請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向區(qū)別詳解,請(qǐng)求轉(zhuǎn)發(fā)和請(qǐng)求重定向,但二者是完全不同的,所以我們今天就來盤他們的區(qū)別介紹,需要的朋友可以參考一下
    2022-07-07
  • Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式

    Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式

    這篇文章主要分享了Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • spring?boot入門之誕生背景及優(yōu)勢(shì)影響

    spring?boot入門之誕生背景及優(yōu)勢(shì)影響

    這篇文章主要為大家描述說明了介紹了spring?boot誕生的背景以及其產(chǎn)生的優(yōu)勢(shì)影響,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • SpringCloud Nacos作為配置中心超詳細(xì)講解

    SpringCloud Nacos作為配置中心超詳細(xì)講解

    這篇文章主要介紹了Springcloud中的Nacos作為配置中心,本文以用戶微服務(wù)為例,進(jìn)行統(tǒng)一的配置,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 三分鐘讀懂mybatis中resultMap和resultType區(qū)別

    三分鐘讀懂mybatis中resultMap和resultType區(qū)別

    這篇文章主要給大家介紹了mybatis中resultMap和resultType區(qū)別的相關(guān)資料,resultType和resultMap都是mybatis進(jìn)行數(shù)據(jù)庫(kù)連接操作處理返回結(jié)果的,需要的朋友可以參考下
    2023-07-07
  • mybatis報(bào)錯(cuò)?resultMapException的解決

    mybatis報(bào)錯(cuò)?resultMapException的解決

    這篇文章主要介紹了mybatis報(bào)錯(cuò)?resultMapException的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java中使用xls格式化xml的實(shí)例

    java中使用xls格式化xml的實(shí)例

    這篇文章主要介紹了java中調(diào)用xls格式化xml的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • Spring的@Conditional詳解

    Spring的@Conditional詳解

    這篇文章主要介紹了Spring的@Conditional詳解,給想要注入Bean增加限制條件,只有滿足限制條件才會(huì)被構(gòu)造并注入到Spring的IOC容器中,通常和@Bean注解一起使用,需要的朋友可以參考下
    2024-01-01

最新評(píng)論