订单表主键是 int,跑到 21 亿多突然插不进去,报 Duplicate entry,查了半天才发现是溢出了。int范围这条线,平时没人注意,出事就是大事故。

32 位有符号整数的边界

最常见的 int 是 32 位有符号,范围 -2147483648 到 2147483647,也就是负 2 的 31 次方到 2 的 31 次方减 1。正数只到 21 亿出头。16 位 short 是 -32768 到 32767,64 位 long 是 -9223372036854775808 到 9223372036854775807。无符号 32 位从 0 开始,最大 4294967295。

Java 的 int 固定 32 位。C 语言标准只保证至少 16 位,实际看编译器和平台,多数桌面环境是 32 位。MySQL 的 INT 默认有符号,写 INT UNSIGNED 才是 0 到 42 亿;增长快的业务直接上 BIGINT。

数据库里还有几个容易混的类型:TINYINT 占 1 字节,范围 -128 到 127;SMALLINT 占 2 字节,-32768 到 32767;MEDIUMINT 占 3 字节。建表按数据量选,别一律写 INT,字段注释里注明范围,后来人改起来有依据。

溢出之后会发生什么

C 和 C++ 的有符号溢出是未定义行为,可能变负数,也可能被编译器优化掉,别指望它按位回绕。Java 的 int 溢出会静默回绕,2147483647 加 1 等于 -2147483648,所以有 Math.addExact 这种会抛异常的方法。Python 的 int 没有上限,内存够就能存。JavaScript 的 Number 安全整数只到 2 的 53 次方减 1,即 9007199254740991,再大要用 BigInt。

选类型时按业务峰值留余量。用户 ID、订单号这种只增不减的,直接 BIGINT;状态码、年龄用 tinyint 或 int 都行。接口传参也要注意,前端 JS 拿到超过 2 的 53 次方的 long 会失真,后端常把 ID 转成字符串返回。

int范围 记住 21 亿这条线,估算三年内可能超过,就别省那 4 个字节。改字段类型比修线上数据便宜得多。