安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

MySQL主键自增值为什么有空洞?

4月8日 藏于心投稿
  GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  1。场景准备2。开始测试3。问题分析4。问题拓展
  本文在测试insert、insertignore、replaceinto三种数据插入方式的时候,发现插入数据的时候在表内存在带有唯一特性的值重复的情况下三种语句的处理方式。最终发现了MySQL主键自增值空洞了1。场景准备
  测试场景为MySQL8。0:主键重复场景唯一键重复场景
  1、建表,包含主键及唯一约束CREATETABLEt1(idint(11)NOTNULLautoincrement,c1varchar(64)DEFAULTNULL,c2int(11)DEFAULTNULL,PRIMARYKEY(id),UNIQUEKEYukc1(c1))ENGINEInnoDBDEFAULTCHARSETutf8;
  2、写入初始测试数据insertintot1(c1,c2)values(a,1),(b,2),(c,3);mysqlselectfromt1;idc1c21a12b23c33rowsinset(0。00sec)2。开始测试insertinto测试主键重复mysqlinsertintot1values(1,aaa,111);ERROR1062(23000):Duplicateentry1forkeyt1。PRIMARY测试唯一键重复mysqlinsertintot1(c1,c2)values(a,4);ERROR1062(23000):Duplicateentryaforkeyt1。ukc1insertignoreinto
  insert方式插入数据在处理过程中发生主键传统等错误时候,语句会被终止,并告知错误的原因。而使用insertignore的方式进行数据插入,则会忽略插入错误的行继续插入没有问题的行记录,最终以warning进行提示。测试主键重复mysqlinsertignoreintot1values(1,aaa,111);QueryOK,0rowsaffected,1warning(0。00sec)LevelCodeMessageWarning1062Duplicateentry1forkeyt1。PRIMARY1rowinset(0。01sec)测试唯一键重复mysqlinsertignoreintot1(c1,c2)values(a,4);QueryOK,0rowsaffected,1warning(0。00sec)LevelCodeMessageWarning1062Duplicateentryaforkeyt1。ukc11rowinset(0。00sec)
  在测试过程中惊奇地发现测试表中的主键自增列发生了改变,经过之前的操作已经变成了7:mysqlshowcreatetablet1G1。rowTable:t1CreateTable:CREATETABLEt1(idintNOTNULLAUTOINCREMENT,c1varchar(64)DEFAULTNULL,c2intDEFAULTNULL,PRIMARYKEY(id),UNIQUEKEYukc1(c1))ENGINEInnoDBAUTOINCREMENT7DEFAULTCHARSETutf8mb31rowinset(0。00sec)可是表的行数据并没有增加mysqlselectfromt1;idc1c21a12b23c33rowsinset(0。00sec)新写入一条数据后,自增id变成7mysqlinsertintot1(c1,c2)values(d,4);QueryOK,1rowaffected(0。00sec)mysqlselectfromt1;idc1c21a12b23c37d44rowsinset(0。00sec)replaceinto
  最后,replaceinto的方式导致如果插入数据是原值的情况,然后主键冲突,就对该主键的内容进行替换,如果唯一键冲突,唯一值所在行就会删除,重新插入新的行,如果都不冲突则正常插入数据。测试主键重复mysqlreplaceintot1values(1,aaa,111);QueryOK,2rowsaffected(0。00sec)mysqlselectfromt1;idc1c21aaa1112b23c37d44rowsinset(0。00sec)测试唯一键重复mysqlreplaceintot1(c1,c2)values(b,4);QueryOK,2rowsaffected(0。01sec)mysqlselectfromt1;idc1c21aaa1113c37d48b44rowsinset(0。00sec)
  上文测试了三种插入数据的方式,可是测试过程中发现插入失败的时候,自增列的自增值居然变大了。3。问题分析
  为了更好地理解,首先让我们具体认识一下AUTOINCREMENT属性在不同的存储引擎当中,其自增值的保存策略有所不同:MyISAM引擎的自增值是保存在数据文件中的。InnoDB引擎的自增值,其实是保存在了内存里,并且到了MySQL8。0版本后,将自增值的变更记录在了redolog中,当MySQL发生重启的时候依靠redolog恢复重启之前的自增值。在此前,现在该表的自增值是7,重启后又变成4了。
  可是理解了这个并不能马上理解现在的这个问题,我们知道当数据进行数据插入的时候,如果插入的数据中自增列不指定其值的时候,该列就会以当前自增值作为其值,如果指定其值就会插入指定的值,当然也有满足唯一的原则,同时插入指定值大于自增值时,自增值也会随之改变。而自增值使用的算法是以autoincrementoffset参数决定开始,以autoincrementincrement决定步长来实现的,默认情况都是1:autoincrementoffset11rowinset(0。00sec)autoincrementincrement11rowinset(0。00sec)
  那么,为什么会出现插入数据未成功,自增值却变大了的情况呢?原因很简单,用插入数据的流程来进行分析:
  因为自增值的保存是在插入数据真正执行前完成的,因此就会出现这种问题了。
  这个时候有人就会想了,可以把AUTOINCREMENT值改回去吗?简单测试一下:mysqlshowcreatetablet1G1。rowTable:t1CreateTable:CREATETABLEt1(idintNOTNULLAUTOINCREMENT,c1varchar(64)DEFAULTNULL,c2intDEFAULTNULL,PRIMARYKEY(id),UNIQUEKEYukc1(c1))ENGINEInnoDBAUTOINCREMENT9DEFAULTCHARSETutf8mb31rowinset(0。00sec)mysqlselectfromt1;idc1c21a13c37d48b44rowsinset(0。00sec)自增值修改为15mysqlaltertablet1autoincrement15;QueryOK,0rowsaffected(0。01sec)Records:0Duplicates:0Warnings:0修改成功mysqlshowcreatetablet1G1。rowTable:t1CreateTable:CREATETABLEt1(idintNOTNULLAUTOINCREMENT,c1varchar(64)DEFAULTNULL,c2intDEFAULTNULL,PRIMARYKEY(id),UNIQUEKEYukc1(c1))ENGINEInnoDBAUTOINCREMENT15DEFAULTCHARSETutf8mb31rowinset(0。00sec)未插入任何值,修改回去,修改成功mysqlaltertablet1autoincrement9;QueryOK,0rowsaffected(0。02sec)Records:0Duplicates:0Warnings:0mysqlshowcreatetablet1G1。rowTable:t1CreateTable:CREATETABLEt1(idintNOTNULLAUTOINCREMENT,c1varchar(64)DEFAULTNULL,c2intDEFAULTNULL,PRIMARYKEY(id),UNIQUEKEYukc1(c1))ENGINEInnoDBAUTOINCREMENT9DEFAULTCHARSETutf8mb31rowinset(0。00sec)修改回自增中间的值mysqlaltertablet1autoincrement5;QueryOK,0rowsaffected(0。01sec)Records:0Duplicates:0Warnings:0不会报错但无法修改mysqlshowcreatetablet1G1。rowTable:t1CreateTable:CREATETABLEt1(idintNOTNULLAUTOINCREMENT,c1varchar(64)DEFAULTNULL,c2intDEFAULTNULL,PRIMARYKEY(id),UNIQUEKEYukc1(c1))ENGINEInnoDBAUTOINCREMENT9DEFAULTCHARSETutf8mb31rowinset(0。00sec)
  显然,如果自增值往大的方向修改是没有问题的,但如果往小的修改就要看目前数据库插入的值是否会将修改后的自增值卡在中间,如果出现这种情况是没办法改回去的,原因显而易见,自增属性与主键配套使用,如果现在表里id4和id6之间差了个5的值,将自增值改回5,当插入数据时,自增值就会插入5的值并且把自增值加1,问题就出现了,此时自增值再进行插入就违背了唯一的原则了4。问题拓展
  在生产环境中还存在很多类似的问题,如:目前的插入值为8,自增值为9mysqlselectfromt1;idc1c21a13c37d48b44rowsinset(0。00sec)插入数据相当于(9,t1,1)mysqlinsertintot1values(null,t1,1);QueryOK,1rowaffected(0。00sec)开启事务QueryOK,0rowsaffected(0。00sec)插入数据相当于(10,t2,2)mysqlinsertintot1values(null,t2,2);QueryOK,1rowaffected(0。00sec)事务回滚QueryOK,0rowsaffected(0。00sec)插入数据相当于(11,t3,3)mysqlinsertintot1values(null,t3,3);QueryOK,1rowaffected(0。01sec)mysqlselectfromt1;idc1c21a13c37d48b49t1111t336rowsinset(0。00sec)
  在插入过程中,开启了一个事务,在插入的时候发生了事务的回滚,当回滚后再次插入数据,发现自增值又出现了空洞,那么问题又来了,为什么在插入数据的时候发生了回滚,数据回滚了,自增值却没有回滚呢?为了更直观,继续测试,假设有两个事务。
  测试前数据:mysqlselectfromt1;idc1c21a13c37d48b49t1111t3313t437rowsinset(0。00sec)
  进行测试:
  session1
  session2
  
  insertintot1values(null,s1,1);
  insertintot1values(null,s2,2);
  
  
  测试后数据:mysqlselectfromt1;idc1c21a13c37d48b49t1111t3313t4315s228rowsinset(0。00sec)
  发现还是空洞了,而且此时答案也十分清楚了,在不同事务在进行写入操作的时候申请自增值,为了避免两个事务申请到相同的自增值,所以需要对其加锁,按照一定顺序进行申请自增值。根据前面的例子来看:首先两个session都开启了事务,session1前面的是id14的自增值,session2则申请到id15的自增值接着当session2插入成功后提交了事务,而此时,session1插入成功或出现插入失败时进行了事务回滚
  此时就出现了前面说到的问题了,没办法回滚,回滚就会出现自增值卡在中间的情况了,以后有机会再继续聊聊自增锁的问题。
  EnjoyGreatSQL:)
  《深入浅出MGR》视频课程
  戳此小程序即可直达B站
  https:www。bilibili。commedialistplay1363850082?businessspacecollectionbusinessid343928desc0
  文章推荐:MySQL8。0有趣的新特性:CHECK约束MySQL启停过程了解一二技术分享微服务架构的数据库为什么喜欢分库分表?MySQL内存管理机制浅析技术分析浅析MySQL与ElasticSearch的组合使用
  GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。
  Gitee:
  https:gitee。comGreatSQLGreatSQL
  GitHub:
  https:github。comGreatSQLGreatSQLBilibili:
  https:space。bilibili。com1363850082video
  微信QQ群:
  可扫码添加GreatSQL社区助手微信好友,发送验证信息加群加入GreatSQLMGR交流微信群,亦可直接扫码加入GreatSQLMGR交流QQ群。
投诉 评论 转载

五胞胎妈妈坦言,如果重来一个都不要,不是太累,是觉得孩子太苦文家有小甜椒儿(原创不易,请勿抄袭,欢迎个人转载分享)图来源网络(如有侵权请联系删除)还记得曾经轰动一时的奥运五福娃吗?2008年奥运会的时候,五胞胎受邀成为……我国抛出千亿美债后,开始大规模买进美方大豆?外媒或采购更多我国从去年12月开始,到今年5月底,已经连续6个月抛售总计1001亿美债。现如今,我国持有美债规模已经跌破1万亿大关。其实,除了中国之外,还有20多个国家都在不同的程度在减持美……不懂的人买苹果,半懂的人买华为,真正懂的人只要性能够用就行了前不久,国内市场的618手机销量排行榜出炉了,跟往年相比,销量还在衰退,同比降低10,手机整体市场仍不容乐观。显而易见,跟以往相比,现在人们换新手机的欲望明显下降,除非丢失或者……汉EV自驾广西,游览免费的4A景区永安王城,请提前停车自驾广西转眼就快一个月时间了,在广西不一定非得去绕着景区和比较宽阔的大马路行驶你可以选择像我一样地走一些县道或者是乡道,这些路上你会看到不一样的广西,更接近生活的广西,这也是我……TES43XYG,苏沫和湘军赛后拥抱,大喊我们就是最强上野王者荣耀挑战者杯正赛正式拉开帷幕,首场比赛就是XYG对阵长沙TES。这两支队伍在本赛季交手了很多次,常规赛的时候都是TES获胜,但淘汰赛和这次挑战者杯的选拔赛都是XYG获胜。其……时尚之国意大利十大时尚艺术博物馆时尚、艺术、设计、电影。。。。。。是意大利的魅力所在。探索意大利魅力,领略时尚与艺术的最佳方式就是进入当地的博物馆。意大利是文艺复兴的诞生地,意大利艺术家、画家和雕塑家的……张仲景的救阴法,耳朵不响了不失眠了时间也不短了《伤寒论》是医圣张仲景留给后代人的宝贵财富,也是我们中医人必须要传承的精华。这本书以寒证为主,所以治疗方法更多的侧重于辛温,所以也有伤寒法在救阳的说法。但如果多读几遍,细……无期迷途评测不喜欢穿衣服的油腻大姐姐都爱玩的手游关于《无期迷途》,游戏批评最大的疑惑是,不知道这个游戏是怎么过审的,如何能拿到版号。《无期迷途》设立的题材基调,在游戏批评看来过于危险,玩家驱使操控的,是一众主要由女性组……张柏芝景甜同框旧照,好一对豪门姐妹花,盛世美颜无人能挡早年的张柏芝可以说是美艳高贵,不知道大家还是否记得《星语心愿》,那时候的张柏芝正处于颜值巅峰,是众多男人心目中的女神,虽然后面经历了很多事,曾经的女神也慢慢老了。近日,有……将有必死心,士无贪生念,从74军抗战中牺牲的军官看这支抗日铁璿经公号重析抗战史授权转载【本文刊发时恰逢国家公祭日,特以本文缅怀在抗战中英勇牺牲的先烈】在全面抗战的八年时间里,第74军阵亡官兵总数达四万余人。其中绝大多数……重情义的高秀敏为了帮范伟出头,离世前都不愿和赵本山和解2005年8月,57岁何庆魁顶着哭得红肿的眼睛,行尸走肉般操办着大儿子何树春的身后事,他万万没有想到大儿子辉煌的人生刚上轨,就被车祸夺去了生命,留下儿媳妇和一双儿女。……MySQL主键自增值为什么有空洞?GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。1。场景准备2。开始测试3。问题分析4。问题拓展本文在测试insert、insertig……
游戏王怪兽卡鱼族(3)与朋友进行随机VR小游戏对战,MashMeUp即将展开免费公中国移动数智化助力老年客户防范电信网络诈骗A股基建板块卷土重来!这3家优质企业,有望成为新龙头多地提高医保最低缴费年限,男30年女25年,啥信号?保利万科罕见涨停,众生药业天地板,怎么回事?深耕储能赛道,鹏辉能源业绩高增享红利,布局钠电放量在即这三款安卓旗舰手机,除了颜值好看,性能还很强,可以放心闭眼入概率上分析,人类是银河系甚至宇宙唯一智慧物种的可能性有多大?上海双子星赢下柯洁朴廷桓,这是围甲联赛的变通与坚守许褚张辽为什么垃圾,混乱BUG影响很大,陆抗直接生效就很强了上北京做拉皮手术,9天没敢出门,30天的恢复惊艳了身边朋友

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利