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

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

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

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

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

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

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

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

三、idworker使用

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

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

2、向zookeeper注冊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é)點信息,同時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é)點信息,保存本地緩存,開啟定時上報任務(wù)
? ? ? ? ? ? ? ? ? ? nodePath.setWorkerId(zkNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? ? ? zkNodeInfo.setUpdateTime(new Date());
? ? ? ? ? ? ? ? ? ? updateZookeeperNodeInfo(key, zkNodeInfo);
? ? ? ? ? ? ? ? ? ? saveLocalNodeInfo(zkNodeInfo);
? ? ? ? ? ? ? ? ? ? executeUploadNodeInfoTask(key, zkNodeInfo);
? ? ? ? ? ? ? ? ? ? return zkNodeInfo.getWorkerId();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? // 無本地信息或者緩存數(shù)據(jù)不匹配,開始向ZK申請節(jié)點機器ID
? ? ? ? ? ? for (int workerId = 0; workerId < MAX_WORKER_NUM; workerId++) {
? ? ? ? ? ? ? ? String workerIdStr = String.valueOf(workerId);
? ? ? ? ? ? ? ? if (!children.contains(workerIdStr)) { // 申請成功
? ? ? ? ? ? ? ? ? ? NodeInfo applyNodeInfo = createNodeInfo(nodePath.getGroupName(), workerId);
? ? ? ? ? ? ? ? ? ? nodePath.setWorkerId(applyNodeInfo.getWorkerId());
? ? ? ? ? ? ? ? ? ? // 保存ZK節(jié)點信息,保存本地緩存,開啟定時上報任務(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缺點

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

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

相關(guān)文章

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

    JVM 堆和棧的區(qū)別

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

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

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

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

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

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

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

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

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

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

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

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

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

    mybatis報錯?resultMapException的解決

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

    java中使用xls格式化xml的實例

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

    Spring的@Conditional詳解

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

最新評論