好險!一入職,就遇到MySQL這麼大Bug!差點背鍋走人

送你們如下java學習資料





羣裏一網友這兩天剛入職新公司,遇到一個重啓 MySQL 服務後,自動增加值丟失問題,差點背鍋走人。下面咱們一塊兒來回顧一下這個問題。java

在 mysql 中用自增列做爲主鍵時,先往表裏插入 5 條數據,此時表裏數據 id 爲 一、二、三、四、5,若是此時刪除 id=四、5 的數據後,再重啓數據庫,重啓成功後向表裏 insert 數據的時候,INNODB、MyISAM 引擎下 ID 分別是從幾開始增長?若是你沒經歷過,或者當面試時被問到這個問題時,相信多數人都是一臉懵逼。MD 誰有事沒事去重啓線上數據庫嘛。最主要的是不少沒有測試過這個場景,沒有這方面的經驗,我在這裏作個筆記,你們輕噴!mysql

MySQL 一般使用的引擎都是 INNODB,在建表時,通常使用自增列做爲表的主鍵,這樣的表對提升性能有必定的幫助。可是自增列有一個坑,而且這個坑存在了好久,一直到 MySQL 8.0 版本,才修復了這個坑,這個坑就是表的自增列變量 auto\_increment 在 MySQL 重啓後,有可能丟失。面試

  • 「innodb 引擎(低版本):Innodb 表中把自增列做爲主鍵 ID 時,自增列是經過 auto-increment 計數器實現的,計數器的最大值是記錄到內存中的,重啓數據庫後,會致使 auto-increment 計數器重置,從而會致使主鍵 ID 重置。」
  • 「MyISam 引擎:MyISAM 表會把自增列(auto-increment 計數器)最大值是記錄到數據文件裏,重啓 MySQL 自增列(計數器)最大值不會丟失,從而使用自增列做爲主鍵 ID 時也不會丟失。」

innodb 主鍵重置問題

在 MySQL 低版本中,InnoDB 表中使用自增的 auto-increment 計數器 會把值存放在內存中,不會寫入磁盤。一旦 MySQL 服務重啓,這個值就丟了,InnoDB 引擎會根據表中現有的數據從新計算該計數器的值:獲取表中最大的自增主鍵 ID 做爲auto-increment 計數器的最大計數,當 insert 數據時,在 auto-increment 計數器最大值上 1。sql

先建立一張 user 表,新增幾條數據:數據庫

`//1.建立user表:自增列做爲主鍵ID`
``CREATE TABLE `user` (``
 `` `id` int(11) unsigned NOT NULL AUTO_INCREMENT,``
 `` `name` varchar(255) NOT NULL DEFAULT '',``
 `` `age` int(4) unsigned NOT NULL DEFAULT '0',``
 ``PRIMARY KEY (`id`)``
`) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;`
`//2.插入5條數據`
``INSERT INTO `user`(`name`, age) VALUES('劉備1', 21);``
``INSERT INTO `user`(`name`, age) VALUES('劉備2', 22);``
``INSERT INTO `user`(`name`, age) VALUES('劉備3', 23);``
``INSERT INTO `user`(`name`, age) VALUES('劉備4', 24);``
``INSERT INTO `user`(`name`, age) VALUES('劉備5', 25);``

場景一

「mysql 數據庫不重啓時,innodb 自增主鍵 ID 會根據 auto-increment 計數器一直遞增。」性能

向 user 表裏插入 5 條數據,主鍵 ID 按自增列經過 auto-increment 計數器實現自增。學習

圖片

在 user 表裏刪除 id 爲 四、5 的數據,再向 user 表中插入一條數據,主鍵 ID 是 auto-increment 的值 6。測試

圖片

場景二

** mysql 數據庫重啓後,innodb 自增主鍵 ID 會根據 auto-increment 計數器的重置而重置。**spa

在場景一的基礎上,在刪除 id 爲 六、3 的數據後,此時 auto-increment 計數器的值爲 7,user 表裏的 id 最大是 2。code

圖片

而後重啓數據庫後,auto-increment 計數器的值變爲 3,也就是 user 表裏的自增列 ID 的最大值 2 加 1。

圖片

此時在插入數據時,自增 ID 會從 3 開始自增。Innodb 表中把自增列做爲主鍵 ID 時,在 mysql 重啓後就會存在 ID 重置問題。**刪除數據後,再重啓,AUTO\_INCREMENT 會查詢表裏最大 ID 並進行重置,重置後和重啓前AUTO\_INCREMENT 計數器的值不一樣。**在 MyISAM 引擎表中的自增列不會存在這個問題。

圖片

MySQL 8.0 auto-increment 計數器邏輯

在 MySQL 8.0 中,這個計數器的邏輯變了:每當計數器的值有變,InnoDB 會將其寫入 redo log,保存到引擎專用的系統表中。MySQL 正常關閉後重啓:從系統表中獲取計數器的值。MySQL 故障後重啓:從系統表中獲取計數器的值;從最後一個檢查點開始掃描 redo log 中記錄的計數器值;取這二者的最大值做爲新值。

總結

1)若是 mysql 重啓了,那麼 innodb 表在啓動後,AUTO\_INCREMENT 值會自動檢測出、並重置爲當前表中自增列的最大值 +1。2)假如一個表裏 AUTO\_INCREMENT 計數器的值是 10,此時執行update table set id = 15 where id = 9後,若是這時再繼續插入數據,到了自增 ID=15 的時候是會報錯。可是這個時候繼續插入,就不會報錯。由於剛纔即便報錯了,AUTO\_INCREMENT 的值依舊會增長。3)如今使用的通常都是 innodb 引擎,若是將 myisam 引擎轉換過來的時候,必定要當心這個引擎在自增 id 上的不一樣表現。在主從使用不一樣引擎的時候,也會出現問題,最好將引擎改完一致性的。

相關文章
相關標籤/搜索