<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MyBatis-Plus 內(nèi)置雪花算法主鍵重復(fù)問(wèn)題

          共 7212字,需瀏覽 15分鐘

           ·

          2023-10-16 10:31

          程序員的成長(zhǎng)之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享 
          關(guān)注


          閱讀本文大概需要 2.8 分鐘。

          來(lái)自:blog.csdn.net/wagnteng/article/details/117064242

          目前項(xiàng)目使用的id是mybatis-plus 內(nèi)置的主鍵生成策略 ID_WORKER ,最近測(cè)試在做性能壓測(cè),部署架構(gòu)是單服務(wù)集群的部署方式,然后就發(fā)現(xiàn)了id重復(fù)的異常,異常如下

          問(wèn)題分析

          首先分析的是id生成是不是就是重復(fù)了,先關(guān)掉其中一臺(tái)機(jī)器,單機(jī)跑,這個(gè)時(shí)候發(fā)現(xiàn)壓到1000的并發(fā)都沒(méi)有出現(xiàn)過(guò)id重復(fù),這個(gè)說(shuō)明單機(jī)情況下不存在id重復(fù)問(wèn)題,說(shuō)明只有集群的情況下才會(huì)出現(xiàn)。
          再分析一下id生成的幾個(gè)要素,雪花算法的核心能影響到id生成的幾個(gè)因素:
          1. 服務(wù)器時(shí)間
          2. workId(機(jī)器 ID 部分)
          3. datacenterId(數(shù)據(jù)標(biāo)識(shí) ID 部分)。
          先檢查了一下服務(wù)器時(shí)間,都是一樣的,然后再看一下workId的生成,我們先看一下源碼。

          public Sequence() {
              this.datacenterId = getDatacenterId(maxDatacenterId);
              this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
          }
          //獲取workerId
          protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
              StringBuilder mpid = new StringBuilder();
              mpid.append(datacenterId);
              //代表正在運(yùn)行的Java虛擬機(jī)的名稱。
              String name = ManagementFactory.getRuntimeMXBean().getName();
              if (StringUtils.isNotEmpty(name)) {
                  /*
                   * GET jvmPid
                   */

                  mpid.append(name.split(StringPool.AT)[0]);
              }
              /*
               * MAC + PID 的 hashcode 獲取16個(gè)低位
               */

              return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
          }

          這里生成的workerId主要核心影響就是獲取運(yùn)行的虛擬機(jī)名稱,現(xiàn)在猜測(cè)就是有可能是由于兩臺(tái)機(jī)的虛擬機(jī)名稱可能一樣,導(dǎo)致拿到的workerId一樣。這個(gè)沒(méi)有具體去驗(yàn)證,猜測(cè)是這樣的。那我們嘗試修改一下這個(gè)workerId的值。

          問(wèn)題解決

          1.先設(shè)置workerId為隨機(jī)數(shù),這樣保證每個(gè)機(jī)器部署的時(shí)候拿到的都是隨機(jī)數(shù)

          # 設(shè)置隨機(jī)
          mybatis-plus.global-config.worker-id: ${random.int}

          這里你啟動(dòng)項(xiàng)目的時(shí)候回發(fā)現(xiàn)一個(gè)異常
          異常很明顯,這里的worer id 必選小于31,那我們就需要修改一下隨機(jī)數(shù)

          # 設(shè)置隨機(jī)
          mybatis-plus.global-config.worker-id: ${random.int(1,31)}

          這個(gè)時(shí)候我們先看一下我們?cè)O(shè)置參數(shù)有沒(méi)有生效,為了比較明顯看到效果,我們直接設(shè)置worker-id為一個(gè)固定值20,再斷點(diǎn)看一下,我們找到com.baomidou.mybatisplus.core.toolkit.IdWorker這個(gè)核心類,獲取id的核心方法是com.baomidou.mybatisplus.core.toolkit.IdWorker#getId,那我們就在這里加一個(gè)斷點(diǎn)看下

          public class IdWorker {

              /**
               * 主機(jī)和進(jìn)程的機(jī)器碼
               */

              private static Sequence WORKER = new Sequence();
           //獲取id
              public static long getId() {
                  return WORKER.nextId();
              }

              public static String getIdStr() {
                  return String.valueOf(WORKER.nextId());
              }

              /**
               * <p>
               * 有參構(gòu)造器
               * </p>
               *
               * @param workerId     工作機(jī)器 ID
               * @param datacenterId 序列號(hào)
               */

              public static void initSequence(long workerId, long datacenterId) {
                  WORKER = new Sequence(workerId, datacenterId);
              }

              /**
               * <p>
               * 使用ThreadLocalRandom獲取UUID獲取更優(yōu)的效果 去掉"-"
               * </p>
               */

              public static String get32UUID() {
                  ThreadLocalRandom random = ThreadLocalRandom.current();
                  return new UUID(random.nextLong(), random.nextLong()).toString().replace(StringPool.DASH, StringPool.EMPTY);
              }

          }

          斷點(diǎn)后的結(jié)果是:
          這個(gè)時(shí)候看到workerId沒(méi)有生效,我們繼續(xù)分析下源碼。
          項(xiàng)目啟動(dòng)的時(shí)候,mybatis-plus 會(huì)調(diào)用一個(gè)com.baomidou.mybatisplus.core.MybatisConfiguration#init方法來(lái)初始化配置信息,我們看下代碼

          public void init(GlobalConfig globalConfig) {
              // 初始化 Sequence
          //這里需要同時(shí)設(shè)置workerId和datacenterId
              if (null != globalConfig.getWorkerId()
                  && null != globalConfig.getDatacenterId()) {
                  IdWorker.initSequence(globalConfig.getWorkerId(), globalConfig.getDatacenterId());
              }
              // 打印 Banner
              if (globalConfig.isBanner()) {
                  System.out.println(" _ _   |_  _ _|_. ___ _ |    _ ");
                  System.out.println("| | |\\/|_)(_| | |_\\  |_)||_|_\\ ");
                  System.out.println("     /               |         ");
                  System.out.println("                        "+MybatisPlusVersion.getVersion()+" ");
              }
          }

          我們發(fā)現(xiàn)workerId和datacenterId必須同時(shí)設(shè)置才會(huì)獲取我們?cè)O(shè)置的值。
          那我們就修改配置一下

          # 設(shè)置隨機(jī)
          mybatis-plus.global-config.worker-id: ${random.int(1,31)}
          mybatis-plus.global-config.datacenter-id: ${random.int(1,31)}

          這樣設(shè)置以后發(fā)現(xiàn)終于生效了,然后部署一下,問(wèn)題終于解決了。這里問(wèn)題雖然解決了,但是workerId重復(fù)其實(shí)沒(méi)有實(shí)際驗(yàn)證過(guò),如果有驗(yàn)證過(guò)的同學(xué)歡迎留言。
          <END>

          推薦閱讀:

          將 Bean 放入 Spring 容器中的五種方式

          SpringBoot 運(yùn)行內(nèi)存及內(nèi)存參數(shù)設(shè)置:助力高效應(yīng)用部署與優(yōu)化

             
             
          互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

          內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper......等技術(shù)棧!

          ?戳閱讀原文領(lǐng)取!                                  朕已閱 

          瀏覽 163
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美后门菊门交 | 日本一区精品 | 性一乱一交一交一视频 | 欧美精品久久人妻无码免费视频 | 97人妻人人揉人人躁人人 |