版本区别
在MySQL5.7以及之前的版本中自增主值是保存在内存中的,并没有持久化,每次重启之后第一次打开表的时候汇去找自增值的最大值max(ID),然后进行+1操作后作为当前表的自增值。
而在MySQL8.0的版本后,MySQL有了“自增值持久化”的能力,实现了MySQL重启后可以恢复为重启之前的值。8.0版本将自增值的变更记录在redo log 中,重启的时候依靠redo log恢复之前的值。
导致自增主键不连续的原因
- 唯一键冲突会导致自增主键id不连续
插入一条数据时先获取自增值,这是自增值会+1,当插入失败的时候,自增值不会回退 - 事务回滚也会导致自增主键id不连续
和唯一键冲突同样的道理
为什么自增值不能回退
假设有两个并行执行的事务,为了避免两个事务申请到相同的自增值,肯定需要加锁,然后顺序申请:
- 假设事务一申请到了id=1,而事务二申请到了id=2,此时自增值的值为3,然后继续执行
- 如果事务二正确提交了,而事务一出现了唯一键冲突
- 如果允许事务一回退自增id,那么就会出现表中已经存在id=2的记录,而当前的自增id值为1
- 当继续执行其他的事务就会申请到id=2,此时会出现插入语句报错“主键冲突”
有两种方式解决这个主键冲突
- 每次申请id之前,判断表中是否已经存在这个id,如果存在,则跳过这个id,当然这样的效率不高
- 扩大自增id的锁范围,必须等一个事务执行完成并提交,下一个事务才可以再申请id,这样会导致系统并发能力下降。
可见,无论如何都会导致性能问题,所以innodb只能保证自增id是递增的,但不保证是连续的。