一、概述

在数据库应用中,我们经常需要用到自动递增的唯一编号来标识记录。在MySQL中,可通过数据列的auto_increment属性来自动生成。可在建表时可用“auto_increment=n”选项来指定一个自增的初始值。可用“alter table table_name auto_increment=n”命令来重设自增的起始值,当然在设置的时候Mysql会取数据表中auto_increment列的最大值 + 1与n中的较大者作为新的auto_increment值。

Myql的auto_increment属性具有以下特性:

    • 具有auto_increment属性的数据列应该是一个正数序列,如果把该数据列声明为UNSIGNED,这样序列的编号个数可增加一倍。比如tinyint数据列的最大编号是127,如果加上UNSIGNED,那么最大编号变为255
    • auto_increment数据列必须有唯一索引,以避免序号重复;必须具备NOT NULL属性

实际应用中发现,在delete掉某张innoDB表的全部数据并重启Mysql会导致该表的auto_increment列变为1。特测试多种情况下auto_increment列的变化并记录如下。

二、实验

1、innoDB与MyISAM对比

(1)首先,创建一张引擎为innoDB的表测试一下delete掉所有数据然后重启Mysql之后,auto_increment的情况:

mysql> CREATE TABLE `table1` (
-> `id` bigint(20) NOT NULL auto_increment,
-> `create_time` datetime DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected mysql> insert into table1(create_time) values (now());
Query OK, 1 row affected mysql> select * from table1;
+----+---------------------+
| id | create_time |
+----+---------------------+
| 1 | 2017-02-28 16:25:11 |
| 2 | 2017-02-28 16:25:21 |
| 3 | 2017-02-28 16:25:23 |
| 4 | 2017-02-28 16:25:23 |
| 5 | 2017-02-28 16:25:24 |
| 6 | 2017-02-28 16:25:26 |
+----+---------------------+
6 rows in set mysql> delete from table1;
Query OK, 6 rows affected mysql> select * from table1;
Empty set mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table1'; +----------------+
| auto_increment |
+----------------+
| 7 |
+----------------+
1 row in set

可见,执行delete操作清空表之后,表table1的auto_increment值仍然是正常的。重启数据库之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table1';
+----------------+
| auto_increment |
+----------------+
| 1 |
+----------------+
1 row in set

可见,table1表的auto_increment值变成了1。

     结论:innoDB引擎的表,在执行delete清空操作之后,表的auto_increment值不会受到影响;一旦重启Mysql数据库,那么auto_increment值将变成1!

(2)下面我们创建一个引擎为MyISAM的表,测试delete掉所有数据,并重启数据库之后auto_increment的值如何变化:

mysql> CREATE TABLE `table2` (
-> `id` bigint(20) NOT NULL auto_increment,
-> `create_time` datetime DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Query OK, 0 rows affected mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected mysql>
mysql>
mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected mysql> insert into table2(create_time) values (now());
Query OK, 1 row affected mysql> select * from table2;
+----+---------------------+
| id | create_time |
+----+---------------------+
| 1 | 2017-02-28 17:05:22 |
| 2 | 2017-02-28 17:05:25 |
| 3 | 2017-02-28 17:05:26 |
| 4 | 2017-02-28 17:05:27 |
| 5 | 2017-02-28 17:05:28 |
| 6 | 2017-02-28 17:05:29 |
+----+---------------------+
6 rows in set mysql> delete from table2;
Query OK, 6 rows affected mysql> select * from table2;
Empty set mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table2';
+----------------+
| auto_increment |
+----------------+
| 7 |
+----------------+
1 row in set

delete清空操作并不会对table2的auto_increment产生任何影响。重启数据库之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table2';
+----------------+
| auto_increment |
+----------------+
| 7 |
+----------------+
1 row in set

可见,表table2的auto_increment仍然为7。

结论:MyISAM引擎的表,在执行delete操作之后,表的auto_increment值不会受到影响;重启Mysql数据库,auto_increment值也不会受到影响!

2、创建表时指定auto_increment

本节我们测试创建innoDB引擎的表时指定auto_increment会不会对auto_increment产生影响:

mysql> CREATE TABLE `table3` (
-> `id` bigint(20) NOT NULL auto_increment,
-> `create_time` datetime DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB auto_increment=1000 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table3';
+----------------+
| auto_increment |
+----------------+
| 1000 |
+----------------+
1 row in set mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected mysql> insert into table3(create_time) values (now());
Query OK, 1 row affected mysql> select * from table3;
+------+---------------------+
| id | create_time |
+------+---------------------+
| 1000 | 2017-02-28 17:15:13 |
| 1001 | 2017-02-28 17:15:14 |
| 1002 | 2017-02-28 17:15:15 |
| 1003 | 2017-02-28 17:15:15 |
| 1004 | 2017-02-28 17:15:16 |
+------+---------------------+
5 rows in set mysql> delete from table3;
Query OK, 5 rows affected mysql> select * from table3;
Empty set mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table3';
+----------------+
| auto_increment |
+----------------+
| 1005 |
+----------------+
1 row in set

可见,delete操作并不会影响到表table3的auto_increment值。重启数据库之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table3';
+----------------+
| auto_increment |
+----------------+
| 1 |
+----------------+
1 row in set

表table3的auto_increment变成了1。

   结论:在创建innoDB表时,无论指定或不指定auto_increment,delete清空+重启数据库都会使表的auto_increment值变成1。

3、delete的时候添加where 1

本节讨论在执行delete操作时,加where 1:

mysql> CREATE TABLE `table4` (
-> `id` bigint(20) NOT NULL auto_increment,
-> `create_time` datetime DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql>
mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql> insert into table4(create_time) values (now());
Query OK, 1 row affected mysql> select * from table4;
+----+---------------------+
| id | create_time |
+----+---------------------+
| 1 | 2017-02-28 17:21:33 |
| 2 | 2017-02-28 17:21:34 |
| 3 | 2017-02-28 17:21:35 |
| 4 | 2017-02-28 17:21:36 |
| 5 | 2017-02-28 17:21:36 |
| 6 | 2017-02-28 17:21:37 |
| 7 | 2017-02-28 17:21:38 |
+----+---------------------+
7 rows in set mysql> delete from table4 where 1;
Query OK, 7 rows affected mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table4';
+----------------+
| auto_increment |
+----------------+
| 8 |
+----------------+
1 row in set

重启数据库之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table4';
+----------------+
| auto_increment |
+----------------+
| 1 |
+----------------+
1 row in set

可见,网上的所流传的delete清空操作时添加where 1并没用。

   结论:delete innoDB表时,添加或不添加where 1,在数据库重启之后auto_increment都会被重置为1。

4、如果表中有数据,但是数据id小于auto_increment会怎么样?

本节测试当innoDB表中有数据,但是auto_increment列最大的那个值小于表的auto_increment值会怎样。我们先插入一些数据到表中,然后删除末尾的几条数据:

mysql> CREATE TABLE `table5` (
-> `id` bigint(20) NOT NULL auto_increment,
-> `create_time` datetime DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> insert into table5(create_time) values (now());
Query OK, 1 row affected mysql> select * from table5;
+----+---------------------+
| id | create_time |
+----+---------------------+
| 1 | 2017-02-28 17:29:29 |
| 2 | 2017-02-28 17:29:30 |
| 3 | 2017-02-28 17:29:30 |
| 4 | 2017-02-28 17:29:30 |
| 5 | 2017-02-28 17:29:31 |
| 6 | 2017-02-28 17:29:31 |
| 7 | 2017-02-28 17:29:32 |
| 8 | 2017-02-28 17:29:32 |
+----+---------------------+
8 rows in set mysql> delete from table5 where id > 4;
Query OK, 4 rows affected mysql> select * from table5;
+----+---------------------+
| id | create_time |
+----+---------------------+
| 1 | 2017-02-28 17:29:29 |
| 2 | 2017-02-28 17:29:30 |
| 3 | 2017-02-28 17:29:30 |
| 4 | 2017-02-28 17:29:30 |
+----+---------------------+
4 rows in set mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table5';
+----------------+
| auto_increment |
+----------------+
| 9 |
+----------------+
1 row in set

重启数据库之后:

mysql> select auto_increment from information_schema.tables where table_schema = database() and table_name='table5';
+----------------+
| auto_increment |
+----------------+
| 5 |
+----------------+
1 row in set

哇塞,奇迹发生了,table5的auto_increment居然变成了5。由此我们可以得出以下结论。

    结论:Mysql数据库在重启之后,innoDB表的auto_increment值将会被设置为表中auto_increment列的最大值 + 1。

三、深究

为什么会出现上述情况呢?

这是因为,Mysql数据库的的auto_increment值是保存在内存中的,innoDB引擎的表的auto_increment在数据库服务停止时并不会做持久化操作,Mysql会在下次数据库重启的时候,相当于通过执行语句:

select max(id) maxId from table;
alter table auto_increment = maxId + 1;

来设置表table的auto_increment值。

严格意义上来说这是Mysql的一个bug。这个bug将会在8.0版本中得到修复。关于8.0版本的内容的情况,详见:MySQL 8.0.0 版本发布,亮点都在这了! 以及 MySQL 8.0发布,是时候与MyISAM说再见了

因为目前8.0版本稳定版尚未发布,所以目前为了避免被这个bug坑到,只能将引擎换为MyISAM或者从程序上去控制。

转自

Mysql数据库之auto_increment - wangwust - 博客园 https://www.cnblogs.com/wangwust/p/6480044.html

MySQL数据库之auto_increment【转】的更多相关文章

  1. Mysql数据库之auto_increment

    一.概述 在数据库应用中,我们经常需要用到自动递增的唯一编号来标识记录.在MySQL中,可通过数据列的auto_increment属性来自动生成.可在建表时可用“auto_increment=n”选项 ...

  2. mysql 数据库自增id 的总结

    有一个表StuInfo,里面只有两列 StuID,StuName其中StuID是int型,主键,自增列.现在我要插入数据,让他自动的向上增长,insert into StuInfo(StuID,Stu ...

  3. mysql数据库表自增ID批量清零 AUTO_INCREMENT = 0

    mysql数据库表自增ID批量清零 AUTO_INCREMENT = 0 #将数据库表自增ID批量清零 SELECT CONCAT( 'ALTER TABLE ', TABLE_NAME, ' AUT ...

  4. [MySQL数据库之表的约束条件:primary key、auto_increment、not null与default、unique、foreign key:表与表之间建立关联]

    [MySQL数据库之表的约束条件:primary key.auto_increment.not null与default.unique.foreign key:表与表之间建立关联] 表的约束条件 约束 ...

  5. nodejs进阶(6)—连接MySQL数据库

    1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...

  6. 在Ubuntu中建立MySQL数据库

    最近在做一个关于云计算安全系统的项目,需要用到MySQL数据库,现在把建立数据库的步骤记录下来. 一.用命令在Ubuntu上安装MySQL # sudo apt-get update # sudo a ...

  7. mysql数据库表的自增主键号不规律,重新排列

    mysql数据库表的自增主键ID乱了,需要重新排序. 原理:删除原有的自增ID,重新建立新的自增ID. 1.删除原有主键: ALTER TABLE `table_name` DROP `id`; 2. ...

  8. 用户中心mysql数据库表结构的脚本

    /* Navicat MySQL Data Transfer Source Server : rm-m5e3xn7k26i026e75o.mysql.rds.aliyuncs.com Source S ...

  9. mysql数据库权限及编码

    CREATE DATABASE IF NOT EXISTS yourdbname DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 在tigase中,发送消息 ...

随机推荐

  1. spring整合curator实现分布式锁

    为什么要有分布式锁? 比如说,我们要下单,分为两个操作,下单成功(订单服务),扣减库存(商品服务).如果没有锁的话,同时两个请求进来.先检查有没有库存,一看都有,然后下订单,减库存.这时候肯定会出现错 ...

  2. Jenkins自动化部署war项目

    基于上一篇Jenkins安装环境,下面对自动打包部署做个备忘 1.安装:Publish over SSH 插件 2.安装完成后,进入下图配置 ↓↓↓ 3.翻到底下↓↓↓ 找到刚刚安装的Publish ...

  3. Linux记录-salt分析

    salt-master建立分组 如dn: 'L@dnxxx,dyyy' salt -N dn  state.apply  hadoop test=true salt -N dn  cmd.run  ' ...

  4. KMP算法的next[]数组 的求法

    例如: next数组的求解方法是:第一位的next值为0,第二位的next值为1,后面求解每一位的next值时,根据前一位进行比较.首先将前一位与其next值对应的内容进行比较,如果相等,则该位的ne ...

  5. eclipse配置文件乱码

    修改文件打开工具 安装文件编辑器插件 然后搜索

  6. angularjs路由path方式实现原理探究

    angularjs路由 https://angular.io/guide/router 通过URL解释, 来定位客户端生成的浏览器端视图. 你可绑定路由到页面的链接上, 当用户点击链接, 可以浏览到相 ...

  7. GIT好文搜藏

    git图解:代码区域总结 https://zhuanlan.zhihu.com/p/20175919 git跟传统的代码管理器(如:svn)不同, 主要区别在于git多了个本地仓库以及缓存区,所以即使 ...

  8. 使用aspectJ实现Spring AOP的两种方式

    方式一:基于aspectJ的XML配置 方式二:基于aspectJ的注解方式 基于aspectJ的XML配置 1)       引入相关jar包 2)       创建Spring核心配置文件,必须导 ...

  9. 20155324 2016-2017-2 《Java程序设计》第3周学习总结

    20155324 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 定义类 要产生对象必须先定义类,类是对象的设计图,对象是类的实例.类定义时使用class关键 ...

  10. Python非空即真,非零即真

    非空即真,非零即真 #1. 非空即真(只要输入不为空就是真) #username =''(空字典.空字符串.空元组都算空) # a= '' # b=[] # c={} # d=None (返回值是No ...