【MySQL tinyint(1)--------从存储字节到框架映射】

一、底层存储原理

1.1 数据类型本质

  • tinyint 是 MySQL 中最小的整数类型,固定占用 1字节(8位) 存储空间
  • 存储结构:无论 (1) 还是 (255),底层都是 8位二进制 存储
    有符号:1位符号位 + 7位数值位 → -128 到 127
    无符号:8位全数值位 → 0 到 255
    

1.2 显示宽度 (1) 的真相

  • 不是限制存储范围,而是客户端显示提示
  • 仅在使用 ZEROFILL 时生效:tinyint(3) ZEROFILL001, 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 技术对比

维度IntegerBoolean
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 表示已删除,避免重复删除问题

六、框架兼容性矩阵

框架IntegerBoolean推荐
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封禁)也很方便。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值