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

 

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

1
2
3
mysql> create  table  t4 (id int  auto_increment);
ERROR 1075 (42000): Incorrect table  definition; there can be only  one auto column  and  it must be defined as  a key
mysql>

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

1
2
3
mysql>
mysql> create  table  t5 (id int  auto_increment, name  varchar (20) primary  key , key (id));
Query OK, 0 rows  affected (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, 1  row affected ( 0.00  sec)
         
    mysql> select * from t5;
    +----+------+
    | id | name |
    +----+------+
    2  | test |
    +----+------+
    1  row in  set  ( 0.00  sec)
  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, 3  rows affected ( 0.00  sec)
         
    ## 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= 8  DEFAULT CHARSET=utf8
         
    ## 插入 7
    mysql> insert into t2 values ( 7 );
    Query OK, 1  row affected ( 0.00  sec)
         
    ## 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= 8  DEFAULT 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= 8  DEFAULT CHARSET=utf8
    1  row in  set  ( 0.00  sec)
        
    ## 將id= 7 的數據update為 10
    mysql> update t2 set  id= 10  where id= 7 ;
    Query OK, 1  row affected ( 0.00  sec)
    Rows matched: 1   Changed: 1   Warnings: 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= 11  DEFAULT CHARSET=utf8
    1  row in  set  ( 0.00  sec)

    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= 8  DEFAULT CHARSET=utf8
    1  row in  set  ( 0.00  sec)
        
    ## updae更新操作
    mysql> update t3 set  id= 10  where id= 7 ;
    Query OK, 1  row affected ( 0.27  sec)
    Rows matched: 1   Changed: 1   Warnings: 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= 8  DEFAULT CHARSET=utf8
    1  row in  set  ( 0.00  sec)

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

    1
    2
    3
    4
    5
    6
    7
    8
    mysql> insert into t3 values ( null );
    Query OK, 1  row affected ( 0.46  sec)
        
    mysql> insert into t3 values ( null );
    Query OK, 1  row affected ( 0.11  sec)
        
    mysql> insert into t3 values ( null );
    ERROR 1062  ( 23000 ): Duplicate entry '10'  for  key '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> delete  from t3;
    Query OK, 8  rows affected ( 0.34  sec)
       
    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= 18  DEFAULT CHARSET=utf8
    1  row in  set  ( 0.00  sec)

     

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    mysql> truncate table t3;
    Query OK, 0  rows affected ( 0.53  sec)
       
    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
    1  row in  set  ( 0.00  sec)

     

  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= 14  DEFAULT CHARSET=utf8
1  row in  set  ( 0.00  sec)
   
mysql>
mysql> alter table t2 auto_increment= 2 ;
Query OK, 6  rows affected ( 0.04  sec)
Records: 6   Duplicates: 0   Warnings: 0
   
mysql> show create table t2;
+-------+--------------------
  CREATE TABLE `t2` (
   `id` int ( 11 ) NOT NULL AUTO_INCREMENT,
   PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT= 14  DEFAULT 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 var iables 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
set  global auto_increment_increment= 2 ;
set  global 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> set  global auto_increment_increment= 2 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql> show var iables like '%auto_increment%' ;
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 1      |
| auto_increment_offset    | 1      |
+--------------------------+-------+
2  rows in  set  ( 0.00  sec)
  
mysql> show session var iables like '%auto_increment%' ;
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 1      |
| auto_increment_offset    | 1      |
+--------------------------+-------+
2  rows in  set  ( 0.00  sec)
  
mysql> show global var iables like '%auto_increment%' ;      
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 2      |
| auto_increment_offset    | 1      |
+--------------------------+-------+
2  rows in  set  ( 0.00  sec)

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

1
2
set  session auto_increment_increment= 2 ;
set  session 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, 0  rows affected ( 0.00  sec)
  
mysql>
mysql>
mysql> set  session auto_increment_increment= 2 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql> set  session auto_increment_offset= 1 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql> show session var iables like '%auto_incre%' ;
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 2      |
| auto_increment_offset    | 1      |
+--------------------------+-------+
2  rows in  set  ( 0.00  sec)
  
mysql>  insert into t2 values ( null ),( null ),( null ),( null ),( null ),( null );
Query OK, 6  rows affected ( 0.00  sec)
Records: 6   Duplicates: 0   Warnings: 0
  
mysql> select * from t2;
+----+
| id |
+----+
1  |
3  |
5  |
7  |
9  |
| 11  |
+----+
6  rows in  set  ( 0.00  sec)

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, 0  rows affected ( 0.00  sec)
  
mysql>
mysql> set  session auto_increment_increment= 2 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql> set  session auto_increment_offset= 2 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql> show session var iables like '%auto_incre%' ;
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 2      |
| auto_increment_offset    | 2      |
+--------------------------+-------+
2  rows in  set  ( 0.00  sec)
  
mysql>  insert into t2 values ( null ),( null ),( null ),( null ),( null ),( null );
Query OK, 6  rows affected ( 0.00  sec)
Records: 6   Duplicates: 0   Warnings: 0
  
mysql> select * from t2;
+----+
| id |
+----+
2  |
4  |
6  |
8  |
| 10  |
| 12  |
+----+
6  rows in  set  ( 0.00  sec)

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, 0  rows affected ( 0.00  sec)
  
mysql> set  session auto_increment_increment= 10 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql>  set  session auto_increment_offset= 5 ;
Query OK, 0  rows affected ( 0.00  sec)
  
mysql> show session var iables like '%auto_incre%' ;
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| auto_increment_increment | 10     |
| auto_increment_offset    | 5      |
+--------------------------+-------+
2  rows in  set  ( 0.00  sec)
  
mysql> insert into t2 values ( null ),( null ),( null ),( null ),( null ),( null );
Query OK, 6  rows affected ( 0.00  sec)
Records: 6   Duplicates: 0   Warnings: 0
  
mysql> select * from t2;
+----+
| id |
+----+
5  |
| 15  |
| 25  |
| 35  |
| 45  |
| 55  |
+----+
6  rows in  set  ( 0.00  sec)

 

一個很重要的問題:如果在原有的序列中強制插入一個值,比如上面的例子,下一個數據我插入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, 2  rows affected ( 0.01  sec)
Records: 2   Duplicates: 0   Warnings: 0
  
mysql> select * from t2;
+----+
| id |
+----+
5  |
| 15  |
| 25  |
| 35  |
| 45  |
| 55  |
| 57  |
| 58  |
+----+
8  rows in  set  ( 0.00  sec)
  
mysql> insert into t2 values ( null ),( null ),( null );
Query OK, 3  rows affected ( 0.00  sec)
Records: 3   Duplicates: 0   Warnings: 0
  
mysql> select * from t2;
+----+
| id |
+----+
5  |
| 15  |
| 25  |
| 35  |
| 45  |
| 55  |
| 57  |
| 58  |
| 65  |
| 75  |
| 85  |
+----+
11  rows in  set  ( 0.00  sec)