虽然自然数没有上限,但是mysql中整型能够表示的数是有上限的。

表定义自增值id

表定义的自增值达到上限后的逻辑是:再申请下一个id时,得到的值保持不变

232-1(4294967295)不是一个特别大的数,对于一个频繁插入删除数据的表来说,是可能会被用完的。因此在建表的时候你需要考察你的表是否有可能达到这个上限,如果有可能,就应该创建成 8 个字节的 bigint unsigned

InnoDB系统自增row_id

如果没有指定主键,那么innodb会给你自动创建一个不可见的,长度为6个字节的row_id,虽然是6个字节,但是InnoDB在设计的使用是8字节的无符号整型,但是只给row_id是6个字节,当row_id六个字节写满后,就会从0开始进行循环

在 InnoDB 逻辑里,申请到 row_id=N 后,就将这行数据写入表中;==如果表中已经存在 row_id=N 的行,新写入的行就会覆盖原有的行==。

所以还是应该在InnoDB表中组活动创建自增id,这样达到上限之后报错也是能够接受的。

xid

redo log和binlog配合的使用有一个共同的字段叫做xid。

MySQL 内部维护了一个全局变量 global_query_id,每次执行语句的时候将它赋值给 Query_id,然后给这个变量加 1。如果当前语句是这个事务执行的第一条语句,那么 MySQL 还会同时把 Query_id 赋值给这个事务的 Xid

这个变量是一个内存变量,重启之后就清零,不过重启之后也会重新生成新的binlog,所以也能够保证同一个binlog文件里,xid一定是唯一的。

但是如果global_query_id达到上限,继续从0开始计数,从理论上讲,还是会出现同一个binlog里面出现相同xid的场景。不过这个可能性只会在理论上,因为global_query_id是8个字节,太大了。

Innodb trx_id

Xid 是由 server 层维护的。InnoDB 内部使用 Xid,就是为了能够在 InnoDB 事务和 server 之间做关联。但是,InnoDB 自己的trx_id,是另外维护的

InnoDB 内部维护了一个 max_trx_id 全局变量,每次需要申请一个新的 trx_id 时,就获得 max_trx_id 的当前值,然后并将 max_trx_id 加 1。这个值就是在3.事务隔离中提到的事务id。

trx_id是持久化的,重启值也不会清零,所以理论上达到最大值的时候也会出现问题,不过目前还没有mysql实例能够跑到这个bug出现的时间。

thread_id

线程id是mysql中最常见的一种自增id。系统保存了一个全局变量thread_id_counter,每新建一个连接,就将thread_id_counter赋值给这个新连接的线程变量。

thread_id_counter 定义的大小是 4 个字节,因此达到 2^32-1 后,它就会重置为 0,然后继续增加。但是,你不会在 show processlist 里看到两个相同的 thread_id

其分配thread_id的逻辑代码是这样的:

do {
  new_id= thread_id_counter++;
} while (!thread_ids.insert_unique(new_id).second);