我們知道MySQL表可以定義一個自增長的id捏境,如果我們的表沒有指定主鍵字段于游,那MySQL會給我們的表創(chuàng)建一個不可見的,長度為6個自己的row_id垫言,然后不停地往上加步長贰剥,雖然生活中自然數(shù)是沒有上限的,但是在計算機里筷频,我們只要定義了表示這個數(shù)的字節(jié)長度蚌成,那么它就有上限前痘,比如在Java中,int類型的上限值為2^31-1担忧,即2147483647芹缔。MySQL無符號整數(shù)上限為2^32 -1,即4294967295
表的自增id用完了怎么辦
表定義的自增id達(dá)到了上線后瓶盛,再申請下一個id時最欠,得到的值保持不變。
驗證一下:
CREATE TABLE `user` (
? `id` int(20) unsigned NOT NULL AUTO_INCREMENT,
? `name` varchar(10) DEFAULT NULL,
? PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4294967295 DEFAULT CHARSET=utf8;
上面創(chuàng)建了一張user表惩猫,id為自增主鍵芝硬,并且我們把AUTO_INCREMENT設(shè)置成了4294967295,也就是說下次執(zhí)行insert語句的時候id為并且我們把AUTO_INCREMENT設(shè)置成了4294967295:
INSERT INTO `test`.`user` (`name`) VALUES ('張三');
結(jié)果如圖:
同樣我們再執(zhí)行一次insert語句就會報主鍵沖突異常:
MySQL InnoDB系統(tǒng)自增row_id用完了怎么辦
如果我們創(chuàng)建的表沒有指定主鍵轧房,那MySQL會給我們指定一個row_id作為主鍵拌阴。InnoDB維護(hù)了一個全局的dict_sys.row_id值,所有沒有主鍵的InnoDB表奶镶,在每次插入一行數(shù)據(jù)時迟赃,都會將當(dāng)前的dict_sys.row_id值作為要插入數(shù)據(jù)的row_id,然后dict_sys.row_id的值加1厂镇。row_id占用6個字節(jié)長度纤壁,所以row_id也是有范圍的,即row_id值的范圍是從0到2^48(無符號)剪撬。和MySQL自增id不同的是摄乒,如果row_id達(dá)到了上限,下一次取值就從0開始残黑,然后繼續(xù)循環(huán)。如果插入一條數(shù)據(jù)時申請到的row_id比如是0斋否,如果表中沒有row_id為0的數(shù)據(jù)則直接將數(shù)據(jù)插入到表中梨水,但如果表中已經(jīng)有row_id為0的數(shù)據(jù),再插入時就會覆蓋掉原來的數(shù)據(jù)茵臭。
驗證一下:
創(chuàng)建一張沒有主鍵的表:
CREATE TABLE `use_row_id` (
? `name` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后依次執(zhí)行以下語句:
gdb -p 5132 -ex 'p dict_sys.row_id=1' --batch
INSERT INTO `test`.`use_row_id` (`name`) VALUES ('張三');
gdb -p 5132 -ex 'p dict_sys.row_id=281474976710656' --batch
INSERT INTO `test`.`use_row_id` (`name`) VALUES ('李四');
INSERT INTO `test`.`use_row_id` (`name`) VALUES ('王五');
結(jié)果如圖:
從圖中可以看到原來的張三那條數(shù)據(jù)已經(jīng)被覆蓋了疫诽。
總結(jié)
MySQL自增id用完后,再次申請id旦委,得到的值保持不變奇徒。插入數(shù)據(jù)會報主鍵沖突異常。
MySQL InnoDB表未指定主鍵時缨硝,MySQL會指定一個row_id摩钙,如果row_id用完了,則會從頭開始循環(huán)查辩。從這點來說還是建議我們創(chuàng)建表的時候指定主鍵的胖笛,畢竟使用row_id會發(fā)生覆蓋數(shù)據(jù)网持,導(dǎo)致原來的數(shù)據(jù)丟失,影響數(shù)據(jù)的可靠性长踊。