Content #
在多数情况下,自增主键确实表现为连续递增。但是当事务发生冲突时,主键就会跳跃,留下空洞。下面,我用一个例子简单介绍下 MySQL 的处理过程。
两个事务 T1 和 T2 都要在同一张表中插入记录,T1 先执行,得到的主键是 25,而 T2 后执行,得到是 26。
但是,T1 事务还要操作其他数据库表,结果不走运,出现了异常,T1 必须回滚。 T2 事务则正常执行成功,完成了事务提交。
这样,在数据表中就缺少主键为 25 的记录,而当下一个事务 T3 再次申请主键时,得到的就是 27,那么 25 就成了永远的空洞。
为什么不支持连续递增呢?这是因为自增字段所依赖的计数器并不是和事务绑定的。如果要做到连续递增,就要保证计数器提供的每个主键都被使用。
怎么确保每个主键都被使用呢?那就要等待使用主键的事务都提交成功。这意味着,必须前一个事务提交后,计数器才能为后一个事务提供新的主键,这个计数器就变成了一个表级锁。
显然,如果存在这么大粒度的锁,性能肯定会很差,所以 MySQL 优先选择了性能,放弃了连续递增。至于那些因为事务冲突被跳过的数字呢,系统也不会再回收重用了,这是因为要保证自增主键的单调递增。