前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次Auto Increment故障

记一次Auto Increment故障

作者头像
LA0WAN9
发布2021-12-14 08:24:09
3620
发布2021-12-14 08:24:09
举报
文章被收录于专栏:火丁笔记

实际上本次故障的素材来自于朋友的朋友,虽然我并不是故障的亲身经历者,但即便只是作为旁观者,依然感觉有所收获,于是乎记录下来以馈读者。

故障的来龙去脉大致是这样的:在一个月黑风高的晚上,苦逼的程序员被一阵急促的报警短信声惊醒,原来是数据库的某个表出问题了,虽然查询操作都正常,但创建操作却都失败了,经过调试,发现原因是表被插入了一行问题数据,其自增字段的值被显式的设置为整型的最大值,导致后续缺省插入的数据不能获取到一个合法的主键值。

我们不妨创建一个测试表说明问题:

代码语言:javascript
复制
CREATE TABLE IF NOT EXISTS `test` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

然后插入一行问题数据:

代码语言:javascript
复制
INSERT INTO test (id, name) VALUES (2147483647, 'x');

结果导致不能执行正常的插入语句:

代码语言:javascript
复制
INSERT INTO test (name) VALUES ('y');

此时数据库会报错:

#1062 – Duplicate entry ‘2147483647’ for key ‘PRIMARY’

换句话说,InnoDB 表类型会在内部维护一个 Auto Increment 字段的计数器,以便为后续的插入提供一个必要的唯一标识。每当有新数据插入的时候,计数器的值就会被更新为 MAX + 1,如果插入唯一标识为 2147483647 的数据,那么计数器将无法正常更新,因为它已经达到了 INT 数据类型的上限。

既然理清了问题的原因,那么第一感觉就是把 Auto Increment 字段的计数器复位,设置到一个合理的值,我们可以在删除问题数据后尝试执行如下语句:

代码语言:javascript
复制
ALTER TABLE test AUTO_INCREMENT = 123;

此方法无疑能够达到目的,但有一个缺点:在 MySQL 中,当 ALTER 一个表时,实际上相当于重新创建了一次表!如果原本数据就很大的话,这个过程将非常缓慢。

让我们再来考虑考虑其它方法,既然问题出在唯一标识的隐式设置上,那么我们不妨换个思路,显式设置唯一标识,比如说通过「SELECT MAX … FOR UPDATE」的方式直接查询得到唯一标识符,并在稍后执行的 INSERT 语句中显式设置。

不过这种方法不够透明,需要修改业务代码,更透明的方法是使用触发器:

代码语言:javascript
复制
CREATE TABLE seq ( 
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `created` timestamp NOT NULL,
   PRIMARY KEY (`id`)
) Engine=InnoDB;

DELIMITER |;
CREATE TRIGGER test_seq BEFORE INSERT ON test
FOR EACH ROW
BEGIN
    INSERT INTO seq (created) VALUES (NOW());
    SET NEW.id = LAST_INSERT_ID();
END;
|;

问题到这里似乎已经解决了,不过在咨询了 @linux流浪猫 之后,意外得到了一个很简单的答案:只要删除问题数据后,重启一下服务即可。实际上文档里有相关描述:

If you specify an AUTO_INCREMENT column for an InnoDB table, the table handle in the InnoDB data dictionary contains a special counter called the auto-increment counter that is used in assigning new values for the column. This counter is stored only in main memory, not on disk. … A server restart also cancels the effect of the AUTO_INCREMENT = N table option in CREATE TABLE and ALTER TABLE statements, which you can use with InnoDB tables to set the initial counter value or alter the current counter value.

正所谓:踏破铁鞋无觅处,得来全不费工夫。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档