<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>

          如果MySQL的自增 ID 用完了,怎么辦?

          共 3298字,需瀏覽 7分鐘

           ·

          2021-11-15 05:26

          作者 | 方志朋

          來源 | https://mp.weixin.qq.com/s/Yqo5PaTtQcQTn4p8BE6SGg

          如果你用過或了解過MySQL,那你一定知道自增主鍵了。每個(gè)自增id都是定義了初始值,然后按照指定步長增長(默認(rèn)步長是1)。雖然,自然數(shù)是沒有上限的,但是我們在設(shè)計(jì)表結(jié)構(gòu)的時(shí)候,通常都會(huì)指定字段長度,那么,這時(shí)候id就有上限了。既然有上限,就總有被用完的時(shí)候,如果id用完了,怎么辦呢?今天就一起來學(xué)習(xí)下吧。

          自增id

          說到自增id,相信你的第一反應(yīng)一定是在設(shè)計(jì)表結(jié)構(gòu)的時(shí)候自定義一個(gè)自增id字段,那么就有一個(gè)問題啦,在插入數(shù)據(jù)時(shí)有可能唯一主鍵沖、sql事務(wù)回滾、批量插入的時(shí)候,批量申請自增值等原因?qū)е伦栽鰅d是不連續(xù)的。

          表定義的自增值達(dá)到上線后的邏輯是:再申請下一個(gè)id的時(shí)候,獲取的是同一個(gè)值(最大值)。大家可以插入sql設(shè)置id是最大值,再insert一條不主動(dòng)設(shè)置id的語句就可以驗(yàn)證這一結(jié)論啦。這個(gè)時(shí)候如果再插入就是報(bào)主鍵沖突咯~

          這里提醒一下:232-1(4294967295)不是一個(gè)特別大的數(shù),對于一個(gè)頻繁插入刪除數(shù)據(jù)的表來說,是可能會(huì)被用完的。因此在建表的時(shí)候你需要考察你的表是否有可能達(dá)到這個(gè)上限,如果有可能,就應(yīng)該創(chuàng)建成 8 個(gè)字節(jié)的 bigint unsigned。

          InnoDB系統(tǒng)自增row_id

          如果你創(chuàng)建的 InnoDB 表沒有指定主鍵,那么 InnoDB 會(huì)給你創(chuàng)建一個(gè)不可見的,長度為 6 個(gè)字節(jié)的 row_id。InnoDB 維護(hù)了一個(gè)全局的 dict_sys.row_id 值,所有無主鍵的 InnoDB 表,每插入一行數(shù)據(jù),都將當(dāng)前的 dict_sys.row_id 值作為要插入數(shù)據(jù)的 row_id,然后把 dict_sys.row_id 的值加 1。

          實(shí)際上,在代碼實(shí)現(xiàn)時(shí) row_id 是一個(gè)長度為8字節(jié)的無符號長整型 (bigint unsigned)。但是,InnoDB 在設(shè)計(jì)時(shí),給 row_id 留的只是 6 個(gè)字節(jié)的長度,這樣寫到數(shù)據(jù)表中時(shí)只放了最后 6 個(gè)字節(jié),所以 row_id 能寫到數(shù)據(jù)表中的值,就有兩個(gè)特征:

          row_id 寫入表中的值范圍,是從 0 到 248-1;

          當(dāng) dict_sys.row_id=2^48時(shí),如果再有插入數(shù)據(jù)的行為要來申請 row_id,拿到以后再取最后 6 個(gè)字節(jié)的話就是 0。

          雖然,2^48這個(gè)數(shù)字已經(jīng)很大了,但是大家要知道 一個(gè)系統(tǒng)是可以跑很久的,那么還是可能達(dá)到上限的,這時(shí)候再申請就會(huì)覆蓋原來的記錄了。因此,盡量不要選擇這種方式!如果您正在學(xué)習(xí)Spring Boot,推薦一個(gè)連載多年還在繼續(xù)更新的免費(fèi)教程:http://blog.didispace.com/spring-boot-learning-2x/

          Xid

          MySQL中redo log 和 binlog 相配合的時(shí)候,它們有一個(gè)共同的字段叫作 Xid。它在 MySQL 中是用來對應(yīng)事務(wù)的。

          MySQL 內(nèi)部維護(hù)了一個(gè)全局變量 global_query_id,每次執(zhí)行語句的時(shí)候?qū)⑺x值給 Query_id,然后給這個(gè)變量加 1。如果當(dāng)前語句是這個(gè)事務(wù)執(zhí)行的第一條語句,那么 MySQL 還會(huì)同時(shí)把 Query_id 賦值給這個(gè)事務(wù)的 Xid。而 global_query_id 是一個(gè)純內(nèi)存變量,重啟之后就清零了。所以在同一個(gè)數(shù)據(jù)庫實(shí)例中,不同事務(wù)的 Xid 也是有可能相同的。

          Innodb trx_id

          InnoDB 內(nèi)部維護(hù)了一個(gè) max_trx_id 全局變量,每次需要申請一個(gè)新的 trx_id 時(shí),就獲得 max_trx_id 的當(dāng)前值,然后并將 max_trx_id 加 1。

          InnoDB 數(shù)據(jù)可見性的核心思想是:每一行數(shù)據(jù)都記錄了更新它的 trx_id,當(dāng)一個(gè)事務(wù)讀到一行數(shù)據(jù)的時(shí)候,判斷這個(gè)數(shù)據(jù)是否可見的方法,就是通過事務(wù)的一致性視圖與這行數(shù)據(jù)的 trx_id 做對比。但是這個(gè)過程有臟讀存在,那么這個(gè)id就不會(huì)是原子性的,存在重復(fù)的可能性。

          thread_id

          其實(shí),線程 id 才是 MySQL 中最常見的一種自增 id。平時(shí)我們在查各種現(xiàn)場的時(shí)候,show processlist 里面的第一列,就是 thread_id。

          thread_id 的邏輯很好理解:系統(tǒng)保存了一個(gè)全局變量 thread_id_counter,每新建一個(gè)連接,就將 thread_id_counter 賦值給這個(gè)新連接的線程變量。

          另外,如果您正在學(xué)習(xí)Spring Cloud,推薦一個(gè)連載多年還在繼續(xù)更新的免費(fèi)教程:https://blog.didispace.com/spring-cloud-learning/

          thread_id_counter 定義的大小是 4 個(gè)字節(jié),因此達(dá)到 232-1 后,它就會(huì)重置為 0,然后繼續(xù)增加。結(jié)果跟row_id一樣,就會(huì)覆蓋原有記錄了。

          上面介紹了幾種MySQL自身的一些自增id,其實(shí),實(shí)際運(yùn)用中,我們也可能會(huì)選擇外部的自增主鍵,然后持久化到數(shù)據(jù)庫,以此來代替數(shù)據(jù)庫自身的自增id。下面來說說吧。另外,如果您正在學(xué)習(xí)Spring Cloud,推薦一個(gè)連載多年還在繼續(xù)更新的免費(fèi)教程:https://blog.didispace.com/spring-cloud-learning/

          Redis自增主鍵

          其實(shí)外部自增主鍵的生成方式有很多,為什么我要介紹redis呢?因?yàn)槲易约涸趯?shí)際應(yīng)用中使用發(fā)現(xiàn)它的很多優(yōu)點(diǎn)。

          redis自身是原子性的,因此高并發(fā)也是線程安全的。假設(shè)主鍵字段長度20,我們以時(shí)間+自增數(shù)來構(gòu)成主鍵,例如:8位日期+12自增數(shù)。那么,根據(jù)業(yè)務(wù)性質(zhì)可以決定時(shí)間取年月日或者到毫秒級,那么在毫秒之間自增數(shù)的重復(fù)概率是極小極小的,基本的業(yè)務(wù)都能適用。

          總結(jié)

          上面介紹了好幾種自增id,每種自增 id 有各自的應(yīng)用場景,在達(dá)到上限后的表現(xiàn)也不同:

          1、 表的自增 id 達(dá)到上限后,再申請時(shí)它的值就不會(huì)改變,進(jìn)而導(dǎo)致繼續(xù)插入數(shù)據(jù)時(shí)報(bào)主鍵沖突的錯(cuò)誤

          2、 row_id 達(dá)到上限后,則會(huì)歸 0 再重新遞增,如果出現(xiàn)相同的 row_id,后寫的數(shù)據(jù)會(huì)覆蓋之前的數(shù)據(jù)

          3、 Xid 只需要不在同一個(gè) binlog 文件中出現(xiàn)重復(fù)值即可。雖然理論上會(huì)出現(xiàn)重復(fù)值,但是概率極小,可以忽略不計(jì)

          4、 InnoDB 的 max_trx_id 遞增值每次 MySQL 重啟都會(huì)被保存起來,所以我們文章中提到的臟讀的例子就是一個(gè)必現(xiàn)的 bug,好在留給我們的時(shí)間還很充裕

          5、 thread_id 是我們使用中最常見的,而且也是處理得最好的一個(gè)自增 id 邏輯了

          6、 redis外部自增,毫秒級別,理論上會(huì)出現(xiàn)重復(fù)值,但是概率極小,可以忽略不計(jì)

          7、 其實(shí),每種自增id都有各自的適用場景,大家在平時(shí)使用中可以根據(jù)具體場景再選擇。但是要未雨綢繆,因?yàn)橄到y(tǒng)的運(yùn)行時(shí)間和數(shù)據(jù)的存儲(chǔ),這些都是要考慮在內(nèi)的,綜合考慮,選擇一個(gè)在系統(tǒng)運(yùn)行期間一定不會(huì)出現(xiàn)重復(fù)即刻。你學(xué)會(huì)了嗎?

          往期推薦

          手磨14nm咖啡,傳播性病給60%的實(shí)習(xí)團(tuán)隊(duì)!這樣的簡歷,90%的公司拋出橄欖枝?

          我精通各種技術(shù)體系,因已45歲求職難!

          朝陽群眾舉報(bào)阿里996造成交通嚴(yán)重堵塞!網(wǎng)友:誰舉報(bào)下我們啊...

          手下兩個(gè)應(yīng)屆生,一個(gè)踏實(shí)喜歡加班,一個(gè)技術(shù)強(qiáng)挑活,怎么選?

          吊打何同學(xué)?猛肝24小時(shí),用6000元成本打造 AirDesk!


          技術(shù)交流群

          最近有很多人問,有沒有讀者交流群,想知道怎么加入。加入方式很簡單,有興趣的同學(xué),只需要點(diǎn)擊下方卡片,回復(fù)“加群,即可免費(fèi)加入我們的高質(zhì)量技術(shù)交流群!

          點(diǎn)擊閱讀原文,送你免費(fèi)Spring Boot教程!

          瀏覽 44
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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碰公开 | 欧美成人精品无码 网站 | 天天日日日干 | 欧美日本在线 | 九九在线视频 |