1. 程式人生 > 其它 >Mysql中自增欄位(AUTO_INCREMENT)的一些常識

Mysql中自增欄位(AUTO_INCREMENT)的一些常識

在系統開發過程中,我們經常要用到唯一編號。使用過mysql的人都應該知道,mysql有一個定義列為自增的屬性:AUTO_INCREMENT。

指定了AUTO_INCREMENT的列必須要建索引,不然會報錯,索引可以為主鍵索引,當然也可以為非主鍵索引。(不一定要做主鍵)

1 2 3 mysql> createtablet4 (id intauto_increment); ERROR 1075 (42000): Incorrect tabledefinition; there can be onlyone auto columnandit must be defined asa
key mysql>

下面的定義把t5表的主鍵定義為了name,而非自增的id欄位

1 2 3 mysql> mysql> createtablet5 (id intauto_increment,namevarchar(20) primarykey,key(id)); Query OK, 0 rowsaffected (0.01 sec)

指定了auto_increment的列,在插入時:

  1. 如果把一個NULL插入到一個AUTO_INCREMENT資料列裡去,MySQL將自動生成下一個序列編號。編號從1開始,並1為基數遞增。

  2. 當插入記錄時,沒有為AUTO_INCREMENT明確指定值,則等同插入NULL值。

    1 2 3 4 5 6 7 8 9 10 mysql> insert into t5 (id,name) values (null,'test'); Query OK, 1row affected (0.00sec) mysql> select * from t5; +----+------+ | id | name | +----+------+ | 2| test | +----+------+ 1row inset(0.00sec)
  3. 上面語句等同於下面語句:

    1 mysql> insert into t5 (name) values (
    'test');
  4. 當插入記錄時,如果為AUTO_INCREMENT欄位明確指定了一個數值,則會出現兩種情況:

    情況一,如果插入的值與已有的編號重複,則會出現出 錯資訊,因為AUTO_INCREMENT資料列的值必須是唯一的;

    情況二,如果插入的值大於已編號的值,則會把該插入到資料列中,並使在下一個編號將從這個新值開始遞增。

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ## 初始表 mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ## 插入資料 mysql> insert into t2 values (null),(null),(null); Query OK, 3rows affected (0.00sec) ## auto_increment變成4 mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=8DEFAULT CHARSET=utf8 ## 插入7 mysql> insert into t2 values (7); Query OK, 1row affected (0.00sec) ## auto_increment變成8 mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=8DEFAULT CHARSET=utf8

    換句話說,就是自增欄位可以跳過一些編號。

  5. 對於MyISAM表,如果用UPDATE命令更新自增列,如果列值與已有的值重複,則會出錯。如果大於已有值,則下一個編號從該值開始遞增。但是對於innodb表,update auto_increment欄位,會導致發生報錯

    MyISAM表的update如下所示

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ## 當前狀態 mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=8DEFAULT CHARSET=utf8 1row inset(0.00sec) ## 將id=7的資料update為10 mysql> update t2 setid=10where id=7; Query OK, 1row affected (0.00sec) Rows matched: 1Changed: 1Warnings: 0 ## 最新的auto_increment變為11 mysql> show create table t2\G; *************************** 1. row *************************** Table: t2 Create Table: CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=11DEFAULT CHARSET=utf8 1row inset(0.00sec)

    Innodb表的update操作如下所示

    (可以看到在update前後,表定義語句沒有變化),接著執行insert會導致主鍵錯誤!

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 mysql> show create table t3\G; *************************** 1. row *************************** Table: t3 Create Table: CREATE TABLE `t3` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8DEFAULT CHARSET=utf8 1row inset(0.00sec) ## updae更新操作 mysql> update t3 setid=10where id=7; Query OK, 1row affected (0.27sec) Rows matched: 1Changed: 1Warnings: 0 mysql> show create table t3\G; *************************** 1. row *************************** Table: t3 Create Table: CREATE TABLE `t3` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8DEFAULT CHARSET=utf8 1row inset(0.00sec)

    Innodb表繼續插入會導致報錯,但是隻會報錯一次,跳過10之後會正常插入

    1 2 3 4 5 6 7 8 mysql> insert into t3 values (null); Query OK, 1row affected (0.46sec) mysql> insert into t3 values (null); Query OK, 1row affected (0.11sec) mysql> insert into t3 values (null); ERROR 1062(23000): Duplicate entry '10'forkey 'PRIMARY'
  6. 被delete語句刪除的id值,除非sql中將id重新插入,否則前面空餘的id不會複用。

  7. delete from t3該語句不會引起auto_increment的變化,

    1 2 3 4 5 6 7 8 9 10 11 mysql> deletefrom t3; Query OK, 8rows affected (0.34sec) mysql> show create table t3\G; *************************** 1. row *************************** Table: t3 Create Table: CREATE TABLE `t3` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=18DEFAULT CHARSET=utf8 1row inset(0.00sec)

    truncate table t3 該語句會引起auto_increment的變化,從頭開始。

    1 2 3 4 5 6 7 8 9 10 11 mysql> truncate table t3; Query OK, 0rows affected (0.53sec) mysql> show create table t3\G; *************************** 1. row *************************** Table: t3 Create Table: CREATE TABLE `t3` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1row inset(0.00sec)
  8. last_insert_id()函式可獲得自增列自動生成的最後一個編號。但該函式只與伺服器的本次會話過程中生成的值有關。如果在與伺服器的本次會話中尚未生成AUTO_INCREMENT值,則該函式返回0。

修改AUTO_INCREMENT欄位的起始值

可用alter table table_name AUTO_INCREMENT=n命令來重設自增的起始值。

但是如果設定的n比目前的數值小的話,執行的sql不會報錯,但是不會生效!MyISAM和Innodb均是如此。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 mysql> show create table t2; +-------+----------------------- CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=14DEFAULT CHARSET=utf8 1row inset(0.00sec) mysql> mysql> alter table t2 auto_increment=2; Query OK, 6rows affected (0.04sec) Records: 6Duplicates: 0Warnings: 0 mysql> show create table t2; +-------+-------------------- CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=14DEFAULT CHARSET=utf8

auto_increment_increment & auto_increment_offset 兩個變數的介紹

這兩個引數作用:控制自增列AUTO_INCREMENT的行為,用於MASTER-MASTER之間的複製,防止出現重複值。

兩個變數均可以設定為全域性或區域性變數,並且假定每個值都可以為1到65,535之間的整數值。將其中一個變數設定為0會使該變數為1。如果試圖將這些變數設定為大於65,535或小於0的值,則會將該值設定為65,535。如果向將auto_increment_increment或auto_increment_offset設定為非整數值,則會給出錯誤,並且變數的實際值在這種情況下保持不變。

兩個值的含義:

auto_increment_increment:自增值的自增量

auto_increment_offset: 自增值的偏移量

設定了兩個值之後,改伺服器的自增欄位值限定為:

auto_increment_offset + auto_increment_increment*N的值,其中N>=0,但是上限還是要受定義欄位的型別限制。

比如:

auto_increment_offset=1

auto_increment_increment=2

那麼ID則是所有的奇數[1,3,5,7,.....]

如果:

auto_increment_offset=5

auto_increment_increment=10

那麼ID則是所有的奇數[5,15,25,35,.....]

檢視當前值:

1 2 3 4 5 6 7 mysql> show variables like '%auto_increment%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1| | auto_increment_offset | 1| +--------------------------+-------+

配置auto-increment-increment&auto-increment-offset的值:

(1):修改配置檔案,重啟mysqld

vi my.cnf

auto-increment-increment = 2

auto-increment-offset = 2

加入到mysqld相關的配置中

(2):通過set命令修改,不需要重啟mysqld,一般需要用set global來設定

1 2 setglobal auto_increment_increment=2; setglobal auto_increment_offset=2;

注意:在一個會話中,如果用set global 修改了mysql的某個變數值,如果不退出session,重新連線,你用show variables 看到的還是修改之前的值,因為show variables 預設返回的是當前session的值,最好用show session variables 和 show global variables 來檢視對應的變數值。

下面是個例子:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 mysql> setglobal auto_increment_increment=2; Query OK, 0rows affected (0.00sec) mysql> show variables like '%auto_increment%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1| | auto_increment_offset | 1| +--------------------------+-------+ 2rows inset(0.00sec) mysql> show session variables like '%auto_increment%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 1| | auto_increment_offset | 1| +--------------------------+-------+ 2rows inset(0.00sec) mysql> show global variables like '%auto_increment%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 2| | auto_increment_offset | 1| +--------------------------+-------+ 2rows inset(0.00sec)

當然也可以只設定當前session有效

1 2 setsession auto_increment_increment=2; setsession auto_increment_offset=2;

具體的例子:

auto_increment_increment=2

auto_increment_offset=1

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 mysql> truncate t2; Query OK, 0rows affected (0.00sec) mysql> mysql> mysql> setsession auto_increment_increment=2; Query OK, 0rows affected (0.00sec) mysql> setsession auto_increment_offset=1; Query OK, 0rows affected (0.00sec) mysql> show session variables like '%auto_incre%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 2| | auto_increment_offset | 1| +--------------------------+-------+ 2rows inset(0.00sec) mysql> insert into t2 values (null),(null),(null),(null),(null),(null); Query OK, 6rows affected (0.00sec) Records: 6Duplicates: 0Warnings: 0 mysql> select * from t2; +----+ | id | +----+ | 1| | 3| | 5| | 7| | 9| | 11| +----+ 6rows inset(0.00sec)

auto_increment_increment=2

auto_increment_offset=2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 mysql> truncate t2; Query OK, 0rows affected (0.00sec) mysql> mysql> setsession auto_increment_increment=2; Query OK, 0rows affected (0.00sec) mysql> setsession auto_increment_offset=2; Query OK, 0rows affected (0.00sec) mysql> show session variables like '%auto_incre%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 2| | auto_increment_offset | 2| +--------------------------+-------+ 2rows inset(0.00sec) mysql> insert into t2 values (null),(null),(null),(null),(null),(null); Query OK, 6rows affected (0.00sec) Records: 6Duplicates: 0Warnings: 0 mysql> select * from t2; +----+ | id | +----+ | 2| | 4| | 6| | 8| | 10| | 12| +----+ 6rows inset(0.00sec)

auto_increment_increment=10

auto_increment_offset=5

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 mysql> truncate t2; Query OK, 0rows affected (0.00sec) mysql> setsession auto_increment_increment=10; Query OK, 0rows affected (0.00sec) mysql> setsession auto_increment_offset=5; Query OK, 0rows affected (0.00sec) mysql> show session variables like '%auto_incre%'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | auto_increment_increment | 10| | auto_increment_offset | 5| +--------------------------+-------+ 2rows inset(0.00sec) mysql> insert into t2 values (null),(null),(null),(null),(null),(null); Query OK, 6rows affected (0.00sec) Records: 6Duplicates: 0Warnings: 0 mysql> select * from t2; +----+ | id | +----+ | 5| | 15| | 25| | 35| | 45| | 55| +----+ 6rows inset(0.00sec)

一個很重要的問題:如果在原有的序列中強制插入一個值,比如上面的例子,下一個資料我插入57,那再往後生成的值會受前面插入資料的影響嗎?

答案是: 不會的!!

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 mysql> insert into t2 values (57),(58); Query OK, 2rows affected (0.01sec) Records: 2Duplicates: 0Warnings: 0 mysql> select * from t2; +----+ | id | +----+ | 5| | 15| | 25| | 35| | 45| | 55| | 57| | 58| +----+ 8rows inset(0.00sec) mysql> insert into t2 values (null),(null),(null); Query OK, 3rows affected (0.00sec) Records: 3Duplicates: 0Warnings: 0 mysql> select * from t2; +----+ | id | +----+ | 5| | 15| | 25| | 35| | 45| | 55| | 57| | 58| | 65| | 75| | 85| +----+ 11rows inset(0.00sec)

innodb引擎,mysql8.0版本,在update前後,表定義語句有變化,如下:

mysql> select * from test;
+----+------+
| id | name |
+----+------+
| 1 | haha |
| 2 | lala |
+----+------+
2 rows in set (0.00 sec)

mysql> show create table test\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`name`),
KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> update test set id=5 where id=2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> show create table test\G;
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`name`),
KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

變成了6,而不是原來的3

1、相關的引數:

show VARIABLES like '%auto_increment%';
auto_increment_increment
auto_increment_offset

可以通過set語句進行修改,但是重啟伺服器之後會重新變為1

SET auto_increment_increment=2;
SET auto_increment_offset=5;
2、在MyISAM和Innodb兩種儲存引擎下二者的不同:

重啟伺服器之後,Innodb型別系統會維護種子序列的最大值為當前資料的最大值,而MyISAM則保持與重啟前一致。