前言
如果你见过int(4)
,又发现它能写入10000、100000甚至更大的数据,那么本文可以帮你稍解疑惑。
先划重点:int
是定长字段,存储开销固定是4个字节。
关于MySQL所有字段的字段长度、存储开销,可参考《MySQL所有类型的长度范围、存储开销(区分显示宽度/有无符号)》
既然是定长字段,那这个4
就很扎眼了。它就是接下来要说的显示宽度:仅表示存储值不足4
位时、显示为4个字符的宽度。
适用字段类型
MySQL的整数类型都支持显示宽度,但仅影响数字的显示,对数据存储没有影响(整数类型都是定长)。
显示宽度为可选扩展属性,字段声明时可不写。
从MySQL 8.0.17开始,整数类型已经不推荐使用显示宽度,所以声明类型是建议不写。
计算与填充方式
显示宽度按字符数计算:
- 存储数据不足显示宽度,用空格补齐;
- 与可选(非标准)的
ZEROFILL
属性一起使用,默认的空格填充将替换为零;例如,列INT(4) ZEROFILL
,值5
将显示为0005
- 如果指定
ZEROFILL
数字列,MySQL会自动添加该UNSIGNED 属性 - 从MySQL 8.0.17开始,不推荐对数字类型使用
ZEROFILL
1
- 与可选(非标准)的
- 存储数据超过显示宽度,显示完整数据;
- 显示宽度可超过存储长度,按显示宽度补齐空位。
一般用于表示显示完整数据,比如
INT
最大值10进制只有10位,因此INT(11)
可显示完整数据。但这种方式没有太大必要。
附上实验的截图,可以清晰的看到各种效果:
实际使用
设置了显示宽度后,MySQL结果集中返回的数据,就会按显示宽度组织数据(填充空格或0),但是否使用(按显示宽度显示数据),取决于应用程序。
比如MySQL客户端默认会按显示宽度展现数据,而Java中JDBC
等框架,会按声明的类型处理数据。如果int(4)
字段对应的Java类型是java.lang.Integer
,肯定不会显示宽度(转类型时自动处理),但如果是java.lang.String
,就可以显示了(字符串保留)。
Spring-jdbc源码中数据抽取的逻辑:
// 执行sql成功,提取数据 org.springframework.jdbc.core.JdbcTemplate.query() 221行 > var3 = rse.extractData(rs); // 逐行遍历解析 > org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData() 33行 > results.add(this.rowMapper.mapRow(rs, var3++)); // 逐列遍历,组装数据行 > org.springframework.jdbc.core.ColumnMapRowMapper.mapRow() 27行 > mapOfColumnValues.put(this.getColumnKey(column), this.getColumnValue(rs, i)); // 抽取列元素 > org.springframework.jdbc.support.JdbcUtils.getResultSetValue() 185行 > Object obj = rs.getObject(index); > com.mysql.jdbc.ResultSetImpl.getObject() 2714行 > return this.getInt(columnIndex);
按照上面这样,会自动将MySQL返回的byte数组
转为int
基类型,类型转换时将自动去除左侧的0和空格;如果要保留显示宽度,需要类型转换时使用getString()
而不是getInt
方法
再次提醒:从MySQL 8.0.17
开始,整数类型不推荐使用显示宽度,在将来的MySQL版本中,将删除对整数类型显示宽度的支持。必要的情况下,推荐应用程序使用LPAD()
函数、或者将格式化的数字存储在CHAR
列中。
- 关于MySQL所有字段的字段长度、存储开销,可参考《MySQL所有类型的长度范围、存储开销(区分显示宽度/有无符号)》
- 更多基础命令可参考《https://learn.blog.csdn.net/article/category/9232935》
以上。感谢您的阅读。