不知道大家是不是和我一样,每次给有个列添加 int(11)
的时候都会想,会不会是 int(10)
,偶尔也会发神经的想,如果 int(32)
这样的可否?
这个纠结,恐怕我写完读完这篇文章时还会继续
索性,我们就先来解决这个问题吧。
在前面一章节中我们有提到,int
类型的底层存储采用的是 4
字节,也就是 32 位,这样能够存储的实际最大值为 4 294 967 296
,大家数数一下这个数字,总共有多少位 ?
对的,没错,就是 10
位,所以,感觉 int(11)
这个应该是错误的 ? 实际上,真的错了吗 ?
没有,因为我们演示的是无符号整型的情况,而对于有符号整型,范围是 -2 147 483 648
到 2147483648
,大家数一数最小值,是不是就 11 位了
所以,int(11)
就是这么来的,而且也不会错。
但这到底是什么道理呢 ?
为了搞清楚弄明白,我们就必须去了解 MySQL 是如何对待数据类型上的属性的。
数值类型的宽度显示属性
对于所有的数值类型,MySQL 通过扩展的方式,可以有选择性的在类型的 base 关键字后面的括号中指定 「 整数 」 数据类型的 「 显示宽度 」 。
注意: 我们使用 「」 括号扩起来的 整数 和 显示宽度 两个词。
例如,例如,INT(4)
指定显示宽度为 4 位的 INT
。对于一个类型为 INT(4)
的列,实际存储仍然使用 4 个字节,但显示的时候就有有细微的差别:
- 如果给该列传递的值大于等于四位,比如
5201314
,那么显示的时候会使用原值,也就是显示5201314
- 但如果给该列传递的值小于四位,比如
520
,那么显示的时候就会在左边填充0
,也就是显示位0520
我们举一个例子,假设我们有一个表如下
CREATE TABLE `na` (
n1 INT(4) NOT NULL DEFAULT '0',
n2 INT(4) ZEROFILL NOT NULL DEFAULT '0'
);
然后插入一些数据
mysql> INSERT INTO `na` VALUES(520,520),(5201314,5201314);
Query OK, 2 rows affected (0.04 sec)
Records: 2 Duplicates: 0 Warnings: 0
最后我们看看显示的结果
mysql> SELECT * FROM `na`;
+---------+---------+
| n1 | n2 |
+---------+---------+
| 520 | 0520 |
| 5201314 | 5201314 |
+---------+---------+
2 rows in set (0.01 sec)
对比下 n1 和 n2 ,n1 是不是在位数不满足的时候会填充前导的 0
。
从演示结果上来看,显示宽度不会限制可以存储在列中的值的范围,也不会阻止比列显示宽度更宽的值正确显示。例如刚刚的范例,指定为 INT(4)
的列的取值范围为 -2 147 483 648
到 2147483648
,超过四位数允许范围之外的值将使用四位数以上显示
当列添加了 ZEROFILL
约束时 ( 注意,这并不是 SQL 标准的一部分 ),会使用 0
代替默认的默认的空格 ' '
。例如,对于声明为 INT(4) ZEROFILL
的列,会将值 5 显示为 0005
注意
在表达式或 UNION 查询中涉及列时,会自动忽略 ZEROFILL 属性。
使用 ZEROFILL 属性时要注意,如果将大于显示宽度的值存储在具有 ZEROFILL 属性的整数列中,为某些复杂连接生成临时表时可能会遇到问题。因为在这些情况下,MySQL 会假定数据值符合列显示宽度
数值类型的 UNSIGNED 显示属性
所有整数类型都可以具有可选 ( 非标准 ) 属性 UNSIGNED
。无符号类型可用于仅允许列中的非负数或当需要更大的列的上限数字范围时。例如,如果 INT 列为 UNSIGNED,则列的范围大小相同,终端显示时范围从 -2147483648
和 2147483647
更改为 0
和 4294967295
。
从某些方面说,就是 UNSIGNED 属性并不会更改底层的数据存储格式,仍然是 SIGNED
有符号整数,但在显示时,会将有符号的值自动转换为无符号的值。也就是说 UNSIGNED
也是一个显示属性
浮点和精确精度类型也可以是 UNSIGNED
,与整数类型一样,此属性可防止负值存储在列中。但与整数类型不同,列值的上限范围保持不变。
数值类型的 ZEROFILL 显示属性
ZEROFILL 列的属性,我们刚刚介绍过了,这里就不重复介绍了。
如果为数值列指定了 ZEROFILL
,MySQL 会自动添加 UNSIGNED
属性到列中。
数值类型的 AUTO_INCREMENT 属性
整数或浮点数据类型可以添加附加属性 AUTO_INCREMENT
。如果某个列添加了 AUTO_INCREMENT
属性,那么在插入数据的时候,如果不指定该列或者指定该列的值为 NULL
,那么 MySQL 会自动将该列的值设置为下一个序列值
通常,值为 value+1
,其中 value
是表中当前列的最大值。
注意:
AUTO_INCREMENT
序列以1
开始而不是 0
另一个需要注意的是,将 0
存储到 AUTO_INCREMENT
列与存储 NULL
具有相同的效果,除非启用了 NO_AUTO_VALUE_ON_ZERO SQL
模式。
而对于插入 NULL
以生成 AUTO_INCREMENT
值需要将列声明为 NOT NULL
。如果列声明为 NULL,那么插入 NULL
将存储 NULL
。
还有一个需要注意的是,当你将任何其它值插入 AUTO_INCREMENT
列时,该列将设置为该值并重置序列,以便从插入的值开始按顺序执行下一个自动生成的值。所以千万要避免在 AUTO_INCREMENT
指定列值插入,很大概率会发生主键重复的问题
在 MySQL 8.0 及以上的版本, AUTO_INCREMENT
列会自动添加一个隐式的 UNSIGNED
属性来保证插入的值非负。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。