开心一刻
大学期间,跟初恋谈了一段刻骨铭心的恋情,因为某些原因,大学毕业后分手了。
如今大学毕业已经10年,听说她很早就出国了,而我,很早就成的哥了。
昨天,初恋坐上了我的的车,我一眼就认出了她,她亦如当初模样,而我却满脸沧桑。
我不敢打招呼,默默的听着她打电话,讲述着国外的种种。
快到目的地的时候,她放下了电话说:我已经把我这10年的经历都说给你听了,你连句你好都不说吗
我知道电话那头没有任何人,她是故意说给我听的,我哽咽着颤抖的说到:你好
她深情的看着我,问道:我们还回得去吗
我疑惑的望向她,说到:回去?回去可以啊,但得加钱......
TINYINT
关于 TINYINT,我相信大家都知道它,是数据库的一种数据类型,说的详细点,它是数据库的一种数字类型,再详细点,它是数据库的一种整数类型;需要注意的是,它并非 SQL 标准整数类型
SQL标准整数类型:INTEGER(orINT) and SMALLINT
而是某些数据库的拓展整数类型,所以并非所有的关系型数据库都支持 TINYINT,支持的数据库类型包括 MySQL、MariaDB、SQL Server;我们基于 MySQL 来看看 TINYINT
MySQL 官方对整数类型有如下介绍
除了 TINYINT,MySQL 还拓展出了 MEDIUMINT 和 BIGINT,这些都不是 SQL 标准整数类型,在做不同库数据迁移的时候需要考虑这些点
标准 SQL,便于迁移;做表设计的时候,尽量用 SQL 标准数据类型
TINYINT 存储空间占 1 字节,有符号的值范围是 -128 到 127,无符号的值范围是 0 到 255
TINYINT 的基本介绍已经完成,下面开始实操环节,开始之前我先问你们一个问题
在实际项目中,你们一般用 TINYINT 存什么 ?
是不是用来存枚举值?例如这样- `exec_status` TINYINT DEFAULT 0 COMMENT '执行-状态,0:等待中,1:执行中,2:成功,3:失败,4:终止'
复制代码 甚至在枚举值少的时候,会使用 TINYINT(1),对不对?重点来了
TINYINT(1) 中的 1 表示什么?很多小伙伴会理所当然的回答道:数值范围,TINYINT(1) 表示的是数值范围是 -9 到 9,或者 0 ~ 9
对不对呢?我们验证下就知道了。基于 MySQL 8.0.31,我们创建表- CREATE TABLE `tbl_qsl_job` (
- `id` int NOT NULL COMMENT '主键',
- `exec_status` tinyint(1) DEFAULT 0 COMMENT '执行-状态,0:等待中,1:执行中,2:成功,3:失败,4:终止',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB;
复制代码 插入一条记录- INSERT INTO tbl_qsl_job(id, exec_status) VALUES(1, 12);
复制代码 结果会怎么样,超出范围报错?
实际是插入成功
道心是不是碎了一地?
给你们 10 秒钟,收拾下破碎的道心;收拾好了之后我们一起看看官方说明:Numeric Type Attributes
MySQL supports an extension for optionally specifying the display width of integer data types in parentheses following the base keyword for the type. For example, INT(4) specifies an INT with a display width of four digits. This optional display width may be used by applications to display integer values having a width less than the width specified for the column by left-padding them with spaces. (That is, this width is present in the metadata returned with result sets. Whether it is used is up to the application.)
The display width does not constrain the range of values that can be stored in the column. Nor does it prevent values wider than the column display width from being displayed correctly. For example, a column specified as SMALLINT(3) has the usual SMALLINT range of -32768 to 32767, and values outside the range permitted by three digits are displayed in full using more than three digits.
相信你们都能看懂,INT(n) 中的 n 表示的是显示宽度,INT(4) 表示的是显示宽度为四位数的 INT。应用程序可以采用左填充空格的方式来填充宽度不够列指定宽度的整数值(也就是说,此宽度会作为结果集的元数据返回,是否使用取决于应用程序)
显示宽度不会限制列存储的数值范围,也不会截断比列显示宽度更宽的值。例如,SMALLINT(3) 类型的列的存数范围与 SMALLINT 一样,也是 32768 到 32767,超出三位数的值会完整显示
关于整数类型显示宽度,我们可以进行如下总结
类型后面的 n,是显示宽度,表示显示时最少占 n 个字符宽度,既不会限制列存储的数值范围,也不会截断比列显示宽度更宽的值,
显示宽度会作为结果集的元数据返回,是否使用取决于应用程序(这个伏笔,后面会呼应,值得我们留意)
2 变 true
我们把 tbl_qsl_job 中 id = 1 的记录的状态改成 2(因为没有枚举值 12)- UPDATE tbl_qsl_job SET exec_status = 2 WHERE id = 1;
复制代码 基于 SpringBoot 2.7.18、spring-jdbc 5.3.31 、HikariCP 4.0.3、mysql-connector-java 8.0.25 构建查询- package com.qsl;
- import org.junit.jupiter.api.Test;
- import org.springframework.boot.test.context.SpringBootTest;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.jdbc.support.rowset.SqlRowSet;
- import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
- import javax.annotation.Resource;
- /**
- * @author youzb
- */
- @SpringBootTest(classes = Application.class)
- public class QslJobTest {
- @Resource
- private JdbcTemplate jdbcTemplate;
- @Test
- public void getByJdbcTemplate() {
- SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet("SELECT * FROM tbl_qsl_job WHERE id = 1");
- SqlRowSetMetaData metaData = sqlRowSet.getMetaData();
- while (sqlRowSet.next()) {
- for (int i = 1; i <= metaData.getColumnCount(); i++) {
- System.out.print(sqlRowSet.getObject(i) + " ");
- }
- System.out.println();
- }
- }
- }
复制代码 但有个前提,枚举值不能出现负数
调大字段类型显示宽度
直接使用 TINYINT(4) 或 TINYINT
举一反三
既然是 mysql-connector-java 8.0.25 做了默认值的处理,那么 MyBatis-Plus 查的结果是不是也是将 2 处理成 true 呢?我们试一下就知道了,引入 MyBatis-Plus 3.5.7,测试代码很简单- spring:
- datasource:
- url: jdbc:mysql://localhost:3306/fnj_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
复制代码 你们觉得执行结果是怎样的,报错?输出 1 true?还是输出 1 2?执行下就知道了
查询结果正常!
按前面的分析,mysql-connector-java 8.0.25 返回 exec_status 的值是 true,Boolean 强转 Integer 会报错,即使不报错,结果也应该是 1(0 = false,1 = true)嘛,怎么会是 2 呢?
Debug 下你们就明白了
Mybatis 需要将 mysql-connector-java 8.0.25 查到的 ResultSet 映射成 QslJob,就需要用到类型处理器;QslJob 实体的 execStatus 是 Integer 类型的,那肯定用 IntegerTypeHandler 进行处理嘛,自然而然就用到 rs.getInt ,查到的结果自然就是 2 了。
我们再回过头去看 SqlRowSet,如果我们用 sqlRowSet.getInt 替换 sqlRowSet.getObject,是不是就行了?
[code]@Testpublic void getByJdbcTemplate() { SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet("SELECT * FROM tbl_qsl_job WHERE id = 1"); SqlRowSetMetaData metaData = sqlRowSet.getMetaData(); while (sqlRowSet.next()) { for (int i = 1; i |