先给结论:int(5) 中的 5 并不是你最多能存几位数字的限制,也不是存储空间的大小。它是一个历史上的概念,叫作显示宽度。很多开发人员第一次接触这个语法时,会把它和 varchar(5) 里的长度搞混,认为 int(5) 只能保存不超过 99999 的整数。实际上整型列的取值范围由 int 这个类型决定,而不是括号里的数字。接下来把存储、显示和实际约束拆开讲清楚。

一、显示宽度与存储空间无关
在 MySQL 中,int 类型固定占用 4 个字节,无论你写成 int、int(5) 还是 int(11),在磁盘和内存中占用的空间完全一样。4 个字节一共 32 位,有符号整型的范围是 -2147483648 到 2147483647;如果加上 unsigned 属性,范围是 0 到 4294967295。这个范围不会因为括号里的数字变大或变小。
括号中的数字在 MySQL 官方文档中被称为 display width,也就是显示宽度。它最早来自 MySQL 4.x 时代,当时终端查询结果主要是文本表格,有了显示宽度后,客户端可以预留固定的列宽来对齐显示。对于没有 ZEROFILL 的普通整型列,这个宽度基本不起作用,甚至在很多客户端里根本看不出来差异。
可以这样理解:int(5) 只是在告诉 MySQL 这个整数列希望按至少 5 位数字的宽度来展示,但它不会对插入的数据做任何校验或截断。真正决定能存多大数字的,始终是整数类型本身。
二、配合 ZEROFILL 才能看到补零效果
如果想让显示宽度产生实际可见的效果,需要同时使用 ZEROFILL 属性。建表时把某列定义为 int(5) ZEROFILL,MySQL 会在查询结果里对不足 5 位的数字自动补零。例如插入数字 1,查询时显示成 00001,方便编号对齐。
下面这段 SQL 可以直观看到区别:
CREATE TABLE demo_int ( id INT(5) ZEROFILL, normal_id INT(5) ); INSERT INTO demo_int (id, normal_id) VALUES (1, 1), (123456, 123456); SELECT id, normal_id FROM demo_int;
执行后,id 列会显示 00001 和 123456,而 normal_id 列因为没有 ZEROFILL,显示的还是 1 和 123456。特别要注意第二个值:插入 123456 时,虽然超过了 5 位,id 列依然完整返回 123456,并不会变成 23456,也不会报错。这说明显示宽度不参与数据存储,更不会做截断。
补零效果通常用在订单号、批次号、分类编号等场景,让查询结果看起来整齐一些。但它的短板也很明显:一旦数值超过指定宽度,显示就不会再统一。对于需要格式化的编号,在实际系统中更推荐在应用层用字符串填充,而不是依赖 MySQL 的 ZEROFILL。
另外,ZEROFILL 有一个容易被忽略的副作用:带有 ZEROFILL 的列会自动变成无符号类型,不能再插入负数。例如给 int(5) ZEROFILL 列插入 -1,会触发错误或警告,具体行为取决于 SQL 模式。
三、最容易混淆的 varchar(5) 与 int(5)
很多开发者会把 int(5) 当成 varchar(5) 一样理解,认为括号里的数字就是长度上限。但两者有本质区别:varchar(5) 表示最多存储 5 个字符,超过就会报错,或者在非严格模式下被截断;而 int(5) 的 5 只是显示宽度,和存储限制无关。
用一个简单例子比较:
CREATE TABLE demo_length ( num_col INT(3), str_col VARCHAR(3) ); INSERT INTO demo_length (num_col, str_col) VALUES (12345, 'abc');
在上面这段 SQL 中,num_col 可以正常保存 12345,因为 int 的取值范围内它完全合法;但 str_col 如果插入 'abcd',在严格模式下会直接报错,因为字符串长度超过了 3。这个对比非常直观:字符串类型的括号是真正的内容长度限制,而整型括号不是。
还有一种常见误解是 tinyint(1)。有些开发人员以为 tinyint(1) 是布尔类型,实际上 MySQL 里没有独立的布尔类型,tinyint(1) 仍然是整数,可以存储 -128 到 127 或 0 到 255 的值。它只是显示宽度为 1,并不限制只能存 0 和 1。如果要表达布尔语义,建议使用 tinyint(1) 并在应用层做 0/1 校验,或者使用 boolean 别名,但要知道其底层仍是整型。
四、MySQL 8.0 的变更与实践建议
从 MySQL 8.0.17 开始,官方已经弃用了整数类型的显示宽度。也就是说,语句 int(5) 依然能被解析,但会出现弃用警告。较新的版本在建表或修改表时,可能不再在 SHOW CREATE TABLE 中保留括号中的宽度,而是直接显示为 int。这意味着依赖显示宽度的写法在未来版本中会越来越不可控。
如果你正在设计新表,应该尽量避免写 int(5)。需要限制整数范围时,可以用 CHECK 约束把范围限定在业务允许的区间内,例如限制一个字段只能保存 0 到 99999:
CREATE TABLE order_info ( order_no INT CHECK (order_no BETWEEN 0 AND 99999) );
需要固定长度展示的编号,通常建议使用字符串类型存储,比如 char(5) 或 varchar(5),再用 lpad() 等函数在查询时补齐。这样既能控制内容长度,也能统一显示格式,避免整型显示宽度被废弃带来的兼容问题。
最后总结一下:int(5) 的长度既不是存储长度,也不是取值范围,更不是数据位数上限,它只是历史上用于显示对齐的显示宽度。真正决定整型列能存多少的是 int 类型本身,固定 4 字节。日常建表直接写 int、int unsigned 或其他合适的整型即可,不必再写括号里的数字,这样代码更清晰,也能避免同事在阅读表结构时产生误解。

