电子说
前情提要:
最近新接了一个需求,需要去创建两张表,其中有一张表需要根据业务id和业务类型建立唯一索引,对数据唯一性进行约束。
因为涉及到业务嘛,表结构就进行缩略了
表结构示例如下: CREATE TABLE `example_table` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', `business_id` bigint(20) unsigned NOT NULL COMMENT '业务ID', `business_type` tinyint(3) unsigned NOT NULL COMMENT '业务类型,', `del` tinyint(1) unsigned DEFAULT '0' COMMENT '删除标识,0表示未删除,1表示删除', `creator` varchar(50) NOT NULL COMMENT '创建人PIN', `modify_date` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_business_id_and_type` (`business_id`,`business_type`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='示例表'
既然表建立好,那么就是发挥我们编码能力的时候了...此处省略一堆编码时间。
编码结束,自测结束,信心满满的找前端同学进行联调。
因为联调嘛,mock了很多同样的business_id和bussiness_type的数据,结果到了数据库,因为唯一索引的约束,报了一堆错误,插入都失败了。
终于调整了一下mock数据,插入成功了。
但是发生了一个比较神奇的现象
主键不是连续自增的了~~ 中间丢失的自增主键去哪了??
关于自增主键
自增主键是我们在设计数据库表结构时经常使用的主键生成策略,主键的生成可以完全依赖数据库,在新增数据的时候,我们只需要将主键设置为null,0或者不设置该字段,数据库就会为我们自动生成一个主键值。
首先,我们要知道 自增主键保存在哪里~
不同的引擎对于自增值的保存策略不同
1.MyISAM引擎的自增值保存在数据文件中
2.InnoDB引擎的自增值,在MySQL5.7及之前的版本,自增值保存在内存里,并没有持久化。每次重启后,第一次打开表的时候,都会去找自增值的最大值max(id),然后将max(id)+步长(建表语句中的指定步长)作为这个表当前的自增值。在MySQL8.0版本,将自增值的变更记录在了redo log中,重启的时候依靠redo log恢复重启之前的值。
了解了自增主键的保存机制,再了解一下主键这个"自增"逻辑~
插入一条语句分配自增主键id值的流程如图所示。
自增主键不连续的情况
细心的小伙伴一定发现了~咦,这个ID=声明值的话,ID就可以能被随意指定了,那么ID就可能存在不是自增的情况了!
是的,这其实就是第一种自增主键不连续的情况。
第二种不连续的情况就是我们在联调中遇到的问题了
简单来做个测试,目前数据就像一开始的图一样,id自增到了24,下一个插入的应该是25,那么执行一条sql
insert into example_table values (null,111,1,0,'mock',now(),now());
插入成功了一条数据,主键是连续自增的。
那么我们模拟一条错误的sql呢(`creator`字段指定错类型)~:
insert into example_table values (null,112,1,0,mock,now(),now());
果然,执行sql 的时候报出异常:
继续执行一条正确的正常的sql,插入结果:
主键还是连续自增的。这个发生错误为什么自增主键还是连续的呢。我们模拟一下之前联调遇到的情况,插入一条 sql:
insert into example_table values (null,112,1,0,'mock',now(),now());
因为id=26的数据buiness_id和bussiness_type 跟新插入的这条数据一样,那么肯定会因为唯一索引插入不成功,果然,执行结果如下:
那么,我们修改一下sql继续插入呢?
insert into example_table values (null,113,1,0,'mock',now(),now())
主键发生了"断代",27的主键跑丢了...
明明都是sql插入的时候错误,为什么结果会有差异呢,有的时候主键会丢失,有的时候主键不会丢失呢,想要弄明白这个问题,就需要先明白一下一条sql的执行过程:
这里只是针对本文需要关注的点(相信小伙伴对这个执行过程肯定也是非常了解的
审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !