羣裏一網友這兩天剛入職新公司,遇到一個重啓 MySQL 服務後,自動增加值丟失問題,差點背鍋走人。下面咱們一塊兒來回顧一下這個問題。java
在 mysql 中用自增列做爲主鍵時,先往表裏插入 5 條數據,此時表裏數據 id 爲 一、二、三、四、5,若是此時刪除 id=四、5 的數據後,再重啓數據庫,重啓成功後向表裏 insert 數據的時候,INNODB、MyISAM 引擎下 ID 分別是從幾開始增長?若是你沒經歷過,或者當面試時被問到這個問題時,相信多數人都是一臉懵逼。MD 誰有事沒事去重啓線上數據庫嘛。最主要的是不少沒有測試過這個場景,沒有這方面的經驗,我在這裏作個筆記,你們輕噴!mysql
MySQL 一般使用的引擎都是 INNODB,在建表時,通常使用自增列做爲表的主鍵,這樣的表對提升性能有必定的幫助。可是自增列有一個坑,而且這個坑存在了好久,一直到 MySQL 8.0 版本,才修復了這個坑,這個坑就是表的自增列變量 auto\_increment 在 MySQL 重啓後,有可能丟失。面試
在 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 中,這個計數器的邏輯變了:每當計數器的值有變,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 上的不一樣表現。在主從使用不一樣引擎的時候,也會出現問題,最好將引擎改完一致性的。