InnoDB自增列重複值問題

2021-07-11 16:51:05 字數 2255 閱讀 6392

問題重現

先從問題入手,重現下這個bug

use test;

drop table if exists t1;

create table t1(id int auto_increment, a int, primary key (id)) engine=innodb;

insert into t1 values (1,2);

insert into t1 values (null,2);

insert into t1 values (null,2);

select * from t1;

+----+------+

| id | a |

+----+------+

| 1 | 2 |

| 2 | 2 |

| 3 | 2 |

+----+------+

delete from t1 where id=2;

delete from t1 where id=3;

select * from t1;

+----+------+

| id | a |

+----+------+

| 1 | 2 |

+----+------+

這裡我們關閉mysql,再啟動mysql,然後再插入一條資料

insert into t1 values (null,2);

select * from t1;

+----+------+

| id | a |

+----+------+

| 1 | 2 |

+----+------+

| 2 | 2 |

+----+------+

我們看到插入了(2,2),而如果我沒有重啟,插入同樣資料我們得到的應該是(4,2)。 上面的測試反映了mysqld重啟後,innodb儲存引擎的表自增id可能出現重複利用的情況。

自增id重複利用在某些場景下會出現問題。依然用上面的例子,假設t1有個歷史表t1_history用來存t1表的歷史資料,那麼mysqld重啟前,ti_history中可能已經有了(2,2)這條資料,而重啟後我們又插入了(2,2),當新插入的(2,2)遷移到歷史表時,會違反主鍵約束。

原因分析

innodb 自增列出現重複值的原因

mysql> show create table t1\g;

*************************** 1. row ***************************

table: t1

create table: create table `t1` (

`id` int(11) not null auto_increment,

`a` int(11) default null,

primary key (`id`)

) engine=innodb auto_increment=4 default charset=utf8

1 row in set (0.00 sec)

建表時可以指定 auto_increment值,不指定時預設為1,這個值表示當前自增列的起始值大小,如果新插入的資料沒有指定自增列的值,那麼自增列的值即為這個起始值。對於innodb表,這個值沒有持久到檔案中。而是存在記憶體中(dict_table_struct.autoinc)。那麼又問,既然這個值沒有持久下來,為什麼我們每次插入新的值後, show create table t1看到auto_increment值是跟隨變化的。其實show create table t1是直接從dict_table_struct.autoinc取得的(ha_innobase::update_create_info)。

知道了auto_increment是實時儲存記憶體中的。那麼,mysqld 重啟後,從**得到auto_increment呢? 記憶體值肯定是丟失了。實際上mysql採用執行類似select max(id)+1 from t1;方法來得到auto_increment。而這種方法就是造成自增id重複的原因。

myisam自增值

myisam也有這個問題嗎?myisam是沒有這個問題的。myisam會將這個值實時儲存在.myi檔案中(mi_state_info_write)。mysqld重起後會從.myi中讀取auto_increment值(mi_state_info_read)。因此,myisam表重啟是不會出現自增id重複的問題。

問題修復

Sybase IQ自增列identify值的返回

sybase iq自增列identify值的返回 做專案的時候使用到了sybase iq資料庫,由於sybase沒有oracle的sequence概念,在處理插入併發時,一般只能使用到identify自增列,但是這個自增列的值如何獲取,還是需要了解一番的。一般使用如下方法獲取 sql set noc...

oracle自增列的問題

建立表 create table test id number primary key,name varchar2 not null 建立序列 create sequence test seq start with 1 increment by 1 建立觸發器 create or replace t...

mysql 自增列相關問題整理

mysql自增列 1.關鍵字 auto increment 2.自增用法 例 create table animals id mediumint not null auto increment,name char 30 not null,primary key id 3.關於自增 q 怎麼獲得當前的...