数据库里订单号字段设成 INT,跑了一年多,插入开始报 Out of range value for column。查了半天才明白 INT 上限二十多亿,号段早就用完了。
integer 就是整数类型。不同语言、不同数据库的差别集中在三件事:占几位、有没有符号、是不是定长。
范围是算出来的,不用背表
有符号的 n 位整数,范围是负的 2 的 n 减 1 次方,到正的 2 的 n 减 1 次方减 1。32 位就是 -2147483648 到 2147483647,无符号是 0 到 4294967295。记住这个推导,换任何语言都能自己算。
各处的实际表现
- C、C++:int 通常是 32 位,但标准不保证,要确定宽度就用 stdint.h 里的 int32_t
- Java:int 固定 32 位,long 64 位,溢出静默回绕,需要抛错就用 Math.addExact
- MySQL:TINYINT 1 字节、SMALLINT 2 字节、INT 4 字节、BIGINT 8 字节,INT(11) 里的 11 只是显示宽度,不改范围
- Python:int 是任意精度,多大都不溢出,代价是大数运算慢
- PHP:位数跟平台走,64 位系统上就是 64 位
实践里的几条经验
主键、时间戳统一用 BIGINT,省得以后改表。金额如果按分存整数,注意乘除的取整方向,四舍五入和银行家舍入结果不一样。除法也要看清语言:整数除整数在 C、Java、Go 里直接截断,在 Python3 里返回浮点。
还有类型转换的坑。JS 的 Number 是双精度浮点,超过 2 的 53 次方就丢精度,后端返回大整数 ID 必须用字符串,分布式 ID 场景里这个问题非常常见。
取舍很简单:拿不准范围就往上取一档,多占那点存储,远比线上改表便宜。