自增id值的存储方式

innodb在5.8版本前是不对该值进行存储的,只是放在内存中,如果实例重启,则查询表的最大值+1,重新放在内存中。
在5.8以后会将自增值的变更记录在redo log中,重启后依靠redolog恢复重启前值。

自增id修改时机

当执行insert操作时,如果未指定id,或id为0,则会取自增id并将自增值+1;如果指定了id,则会计算指定的id与自增值的大小,如果小的话不会对自增值进行操作,如果大于自增值,则会将自增值修改为该id+1

严格来说并非+1,而是+auto_increment_increment的值

自增锁的范围

在5.1.22版本引入了一个策略,自增参数innodb_autoinc_lock_mod,默认值为1

  • 0: 表示采用5.0版本之前的策略,即语句执行结束才释放锁
  • 1: 普通的insert语句,自增锁在申请之后马上释放;类似insert .... select这样的指插入数据的语句,自增锁还是等语句结束后才释放

insert .... select等语句结束才释放的原因是为了防止备库同步数据由于并且获取自增id导致取的id与主库不同

  • 2: 所有的申请自增主键的动作都是申请后就释放锁

表自增id为什么不是连续的

  • 表的自增id可设置从n开始,每次越过m个值,在分布式存储系统中为了防止id冲突,会使用这种方式
  • 唯一键冲突
  • 事务回滚
  • mysql批量获取自增id,未使用完全
    • 语句执行过程中,第一次申请自增id,会分配1个
    • 第二次申请会分配2个
    • 第三次申请会分配4个
    • 依此类推,同一语句去申请自增id,每次申请到的自增id个数都是上一次的两倍

自增id用完了怎么办

表的自增id达到上限后,再申请时它的值就不会改变,进而导致继续插入数据时,报主键冲突的错误。
如果表未指定自增id,会生成row_id,row_id达到上限后,则会归0再重新递增,如果出现相同的row_id,后写的数据会覆盖之前的数据,row_id的最大值为2的48次方-1

xid&max_trx_id&threadId

Xid是server层维护的,innodb内部使用xid是为了能够在innodb事务和server之间做关联。
xid在实例重启后,会清零,但是mysql在重启后会生成一个新的binlog文件,所以在一个binlog文件中,xid一定是唯一的。虽然理论上xid也会有上限,但是由于重启清零并且该值较大,所以可以忽略

trx_id是innodb内部维护的事务id,当trx_id达到上限后,就会从0开始,这样会导致脏读的情况

thread_id达到最大后,会从0开始,但是当获取新的threadid时,会先判断获取到的threadId是否在用,如果在用则再判断+1之后是否在用,一直取到未在使用的threadId