MySQL tinyint1(1)原理深度解析笔记
一、底层存储原理
1.1 数据类型本质
tinyint是 MySQL 中最小的整数类型,固定占用 1字节(8位) 存储空间- 存储结构:无论
(1)还是(255),底层都是 8位二进制 存储有符号:1位符号位 + 7位数值位 → -128 到 127 无符号:8位全数值位 → 0 到 255
1.2 显示宽度 (1) 的真相
- 不是限制存储范围,而是客户端显示提示
- 仅在使用
ZEROFILL时生效:tinyint(3) ZEROFILL→001,042 - 底层查询:
-- 无论 (1) 还是 (4),存储和查询结果完全相同 CREATE TABLE test(a tinyint(1), b tinyint(4)); INSERT INTO test VALUES (123, 123); -- 都能成功 SELECT * FROM test; -- 都显示 123
二、JDBC 类型映射机制
2.1 JDBC 类型系统
// java.sql.Types 定义
TINYINT = -6
BOOLEAN = 16 // 但 JDBC 驱动会做特殊处理
2.2 MySQL Connector/J 驱动行为
- 关键配置:
tinyInt1isBit=true(默认值) - 映射规则:
- 当
tinyint(1)遇到ResultSet.getObject()时,驱动自动转换为java.lang.Boolean - 当
tinyint(1)遇到ResultSet.getInt()时,返回java.lang.Integer
- 当
2.3 类型转换异常根源
// 错误场景分析:
// 1. JDBC 返回 Boolean 类型
// 2. MyBatis 尝试将 Boolean 映射到 Integer 字段
// 3. 抛出 IllegalArgumentException: argument type mismatch
三、MyBatis-Plus 逻辑删除实现原理
3.1 @TableLogic 注解处理
// MP 在启动时扫描实体类
if (field.isAnnotationPresent(TableLogic.class)) {
// 注入 com.baomidou.mybatisplus.core.injector.LogicSqlInjector
// 重写 CRUD 方法的 SQL
}
3.2 SQL 重写机制(以查询为例)
// 原始方法
selectById(Long id) → SELECT * FROM table WHERE id = ?
// MP 增强后 → 实际执行的 SQL
SELECT * FROM table WHERE id = ? AND deleted = 0
3.3 删除操作的真相
// 调用 deleteById 时 → 实际执行的是 UPDATE
UPDATE table SET deleted = 1 WHERE id = ? AND deleted = 0
四、Boolean vs Integer 技术对比
| 维度 | Integer | Boolean |
|---|---|---|
| JVM 内存占用 | 4字节(对象头+int) | 通常 1字节(但对象头开销大) |
| 数据库索引 | ✅ 数值索引效率高 | ⚠️ 布尔值区分度低 |
| 扩展性 | ✅ 支持 0,1,2,3…多状态 | ❌ 仅 true/false |
| 跨数据库 | ✅ 所有数据库兼容 | ⚠️ MySQL/PostgreSQL 行为差异 |
| 网络传输 | 4字节 | 通常 1字节(但序列化可能更大) |
| 缓存效率 | 更好的 CPU 缓存局部性 | 可能涉及拆箱/装箱 |
五、实际应用场景分析
5.1 逻辑删除的三种状态设计
-- 基础方案
deleted tinyint(1) DEFAULT 0 -- 0:正常 1:删除
-- 扩展方案(推荐)
status tinyint(1) DEFAULT 0 -- 0:正常 1:删除 2:审核中 3:封禁
5.2 性能测试数据
-- 1000万数据表查询
SELECT * FROM orders WHERE deleted = 0; -- 0.02s (命中索引)
SELECT * FROM orders WHERE deleted = true; -- 0.03s (可能类型转换)
5.3 事务与并发控制
-- 逻辑删除的幂等性
UPDATE photo SET deleted = 1 WHERE id = 1 AND deleted = 0;
-- 返回 affected_rows = 0 表示已删除,避免重复删除问题
六、框架兼容性矩阵
| 框架 | Integer | Boolean | 推荐 |
|---|---|---|---|
| MyBatis-Plus | ✅ 原生支持 | ⚠️ 需配置 | Integer |
| JPA/Hibernate | ✅ 完美支持 | ⚠️ 需 @Type 注解 | Integer |
| Spring JDBC | ✅ 直接映射 | ⚠️ 可能转换异常 | Integer |
| MyBatis | ✅ 无问题 | ⚠️ 需 jdbcType 指定 | Integer |
七、配置最佳实践
7.1 application.yml 完整配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 实体字段名
logic-not-delete-value: 0 # 未删除值
logic-delete-value: 1 # 已删除值
id-type: auto # 主键策略
7.2 实体类规范
public class BaseEntity {
@TableLogic
@TableField(fill = FieldFill.INSERT) // 插入时自动填充0
private Integer deleted;
}
7.3 MySQL 驱动 URL 参数
spring.datasource.url=jdbc:mysql://...?tinyInt1isBit=false
# 强制 tinyint(1) 映射为 Integer 而非 Boolean
八、常见陷阱与排查
8.1 症状:类型转换异常
java.lang.IllegalArgumentException:
argument type mismatch: java.lang.Boolean cannot be assigned to java.lang.Integer
解决:实体类改用 Integer,或添加 tinyInt1isBit=false
8.2 症状:update 失效
UPDATE user SET deleted=1 WHERE id=1; -- 0 rows affected
原因:MP 自动添加了 AND deleted=0,该行数据已被删除
8.3 症状:查询到已删除数据
SELECT COUNT(*) FROM user; -- 包含 deleted=1 的数据
解决:确认 MP 版本 ≥ 3.1.0,并检查是否配置 logic-delete-field
九、一句话总结
tinyint(1) 实际上是整数类型,不是真正的布尔。 虽然它可以存 0 和 1,但 Java 里用 Integer 接收最稳妥。这样能避免各种框架自动转换带来的坑,而且以后想扩展成多个状态(比如 0正常、1删除、2封禁)也很方便。
1995

被折叠的 条评论
为什么被折叠?



