mysql+秘密_《MySQL自增ID》告诉你不为人知的“秘密”......

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

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

(1) 它是一个正数序列,如果把该数据列声明为UNSIGNED,编号个数可增加一倍。假如设置的是tinyint类型最大编号是127,如果加上UNSIGNED,那么最大编号变为255

(2) auto_increment数据列必须有唯一索引,以避免序号重复;必须具备NOT NULL属性。

那么,MySQL自增ID用过的都说好用,但是没用对,可能发生灾难...... 为什么这样说?因为我们最近在一个老项目上踩到了MySQL自增ID的大坑,事情是这样的...

神级爆款项目(暂且这样叫)在设计未来合服逻辑时,为了考虑不让ID发生冲突,聪明地在部署每个新服时强制带上服标识号作为自增ID的起始号,例如:

S1101服,部署脚本会强制指定 auto_increment=110100000000 作为该服的自增ID号。

S1102服,部署脚本会强制指定 auto_increment=110200000000 作为该服的自增ID号。

这样一来,在执行合服的过程中是绝对不会发生ID冲突的问题,每个服的玩家ID号是完全唯一的。相信很多项目也是这么设计。。。(我猜的)

但是问题来了,这么好的设计为什么说有坑呢?原因是我们使用了InnoDB作为存储引擎,Innodb引擎的表指定了一个auto_increment列,那么这张表会有一个auto_increment计数器,专门记录当前auto_increment的相关值,用来在insert时为auto_increment列赋值。非常重要的一点是,这个计数值是保存在内存中的,而非磁盘上。

当MySQL运行时,这个计数值随着insert增长。假设表中有100条记录,auto_increment计数值是101,当delete所有的记录后,再insert一条语句,这条语句的id便是101。但是如果把表清空了,再启动MySQL,auto_increment的值就会变为1,因为这个值是InnoDB存储在内存中,如果表中没有任何记录,auto_increment的值是会被重置的。

我们先回到刚才那个神级爆款项目(暂且这样叫),看看这个项目涉及自增ID的表:

由于是一次半夜里机柜意外的断电,导致机器关机自动重启,MySQL和所服游戏服都被重启,重启之后游戏服并没有发生什么异常,也能正常玩。但过两周进行合服的时候,突然报ID冲突了。

百思不得其解啊!明明设计之初就已经规避了的问题。因此对所有自增表进行了扫描,发现以下情况,真的无语了!

86b2672227d532265b2b778b785e66d7.png

机器被重启之前,这个服还没有对外开放,表里还是空的,正常来说部署的时候已经给ID赋值了106800000000,起始号应当是106800000000。当这个服开了之后,ID号就会106800000000+n。正因为机器被重启过,而且表也是空的,导致了ID自增号恢复为1,所以看到上面ID编号不对了,合服时也就发生了ID冲突。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值