哈哈,这个话题其实挺有意思的,很多人写了好几年 Java,可能都没认真想过int(1)和int(10)到底有什么区别。上次我在群里问了下,十个程序员有八个都答错,剩下两个还犹豫半天。
“int(1)” 是一?不是的兄弟
那天我们公司一个新同事写了个表结构,我一看:
CREATE TABLE user (
id INT(1) NOT NULL,
age INT(10),
PRIMARY KEY (id)
);
我问他:“你这是干嘛?id只允许一位数?” 他一脸理所当然地说:“对啊,int(1)不就是最多一位数嘛?”
其实啊,这就是一个超级常见的误区。 在 MySQL 里(注意,是 MySQL,不是 Java),INT(1)里的(1)根本和取值范围没关系。 它只是显示宽度(display width),也就是说,当你启用ZEROFILL时,它会用 0 补齐显示宽度。
举个例子:
CREATE TABLE num_test (
a INT(1) ZEROFILL,
b INT(10) ZEROFILL
);
INSERT INTO num_test VALUES (1, 1);
SELECT * FROM num_test;
查询结果会是:
a | b
-------|----------
0 | 0000000001
看到了吧?数值其实都能存一样的范围,只是显示的时候有区别。INT(1)≠ “只能存一位数”,它照样能存 2,147,483,647。
那 Java 里的 int 呢?
再说回我们熟悉的 Java。 Java 里根本没有 int(1) 这种东西,int就是固定 4 个字节,范围是-2,147,483,648 ~ 2,147,483,647。 没有“括号”的说法。
你在 Java 里写:
int a = 1;
int b = 10;
这俩完全没区别,连类型信息都一样。 如果你用包装类Integer去接,也一样,底层都是 32 位二进制数。
真正的坑:数据库 + Java 的交互
问题来了,当数据库是int(1)的时候,Java 取出来到底是什么?
这时候很多人踩坑。 比如有同事在 MyBatis 里写个映射:
而数据库建表是:
is_active TINYINT(1)
他以为(1)代表 boolean。 结果读出来变成了1或0,再自动映射到boolean类型…… 刚好能用,但语义上非常混乱。
正确的做法其实是:
is_active TINYINT(1) DEFAULT 1 COMMENT '是否启用,0=否 1=是'
然后 Java 里定义为:
private boolean active;
或者你用枚举更安全:
public enum Status {
DISABLED, ENABLED
}
别看(1)好像在暗示布尔值,它其实只是显示宽度的遗留产物。 MySQL 8.0 已经官方移除了INT(M)的显示宽度语义。
我记得有次在做订单系统的时候,表里有个字段叫status INT(2)。 我以为最多两位数,于是写了逻辑:
if (status > 99) {
throw new IllegalArgumentException("状态值异常");
}
结果上线当天直接报错。 因为运营那边加了个新状态 200——他们以为数据库能放。 结果数据库没问题,Java 报错了…… 根本原因就是对(2)理解错了。
延伸:MySQL 各种 int 类型的取值范围
括号里的数字再大也没用——不会限制取值范围。
所以结论其实很简单:
int(1)和int(10)在 Java 里没区别;
在 MySQL 里也没区别,除非你用了ZEROFILL;
(M)表示显示宽度,而不是取值范围;
MySQL 8 以后已经弃用这个特性;
千万别在代码里靠它控制业务逻辑。
其实我第一次知道这个区别还是因为一个线上 bug。 当时有个接口返回的 JSON 把id显示成"0000000012",前端那边还以为是字符串,结果前端强转失败。 后来才发现是因为ZEROFILL把它补成了 10 位。
有时候啊,这种看起来无关紧要的小细节,真能把你坑到凌晨两点。