当前位置: 首页 > news >正文

【Mytais系列】Type模块:类型转换

MyBatis 的 类型系统(Type System) 是框架处理 Java 类型与数据库类型之间映射的核心模块,它通过 类型处理器(TypeHandler)类型别名(TypeAlias)类型转换器 等机制,实现了数据库字段与 Java 对象属性的无缝转换。以下是其核心功能、使用场景及实现原理的详解:


一、类型系统的核心组件

组件

作用

TypeHandler

处理 Java 类型与 JDBC 类型之间的转换(如 StringVARCHAR)。

TypeAlias

为 Java 类型定义别名,简化 XML 配置中的类型名称。

TypeHandlerRegistry

全局注册所有 TypeHandler,管理类型与处理器的映射关系。

ObjectFactory

创建结果集映射的 Java 对象实例(如 POJO、集合等)。


二、类型处理器(TypeHandler)

1. 功能与职责
  • 双向转换
    • 写入数据库:将 Java 对象属性转换为 JDBC 参数(PreparedStatement.setXxx)。
    • 读取数据库:将 JDBC 结果集(ResultSet.getXxx)转换为 Java 对象属性。
  • 支持复杂类型
    • 枚举、集合、自定义对象、JSON 字符串等。
2. 内置 TypeHandler

MyBatis 默认注册了常见类型的处理器,例如:

Java 类型

JDBC 类型

对应 TypeHandler

String

VARCHAR

StringTypeHandler

Integer

INTEGER

IntegerTypeHandler

Date

TIMESTAMP

DateTypeHandler

boolean

BOOLEAN

BooleanTypeHandler

枚举类

VARCHAR

EnumTypeHandler(按名称存储)

枚举类(按序数存储)

INTEGER

EnumOrdinalTypeHandler

3. 自定义 TypeHandler

当默认处理器无法满足需求时(如处理 JSON 字段),可自定义 TypeHandler

示例:将 Java 对象序列化为 JSON 字符串存入数据库

// 1. 实现 TypeHandler 接口
@MappedTypes(User.class)    // 指定处理的 Java 类型
@MappedJdbcTypes(JdbcType.VARCHAR)  // 指定对应的 JDBC 类型
public class JsonTypeHandler implements TypeHandler<User> {private final ObjectMapper objectMapper = new ObjectMapper();// 写入数据库时,将 User 对象转为 JSON 字符串@Overridepublic void setParameter(PreparedStatement ps, int i, User parameter, JdbcType jdbcType) throws SQLException {try {String json = objectMapper.writeValueAsString(parameter);ps.setString(i, json);} catch (JsonProcessingException e) {throw new SQLException("JSON 序列化失败", e);}}// 从数据库读取时,将 JSON 字符串转为 User 对象@Overridepublic User getResult(ResultSet rs, String columnName) throws SQLException {String json = rs.getString(columnName);return parseJson(json);}// 其他重载方法(如 getResult(ResultSet rs, int columnIndex))// ...private User parseJson(String json) {try {return objectMapper.readValue(json, User.class);} catch (JsonProcessingException e) {throw new RuntimeException("JSON 解析失败", e);}}
}

注册自定义 TypeHandler

<!-- mybatis-config.xml -->
<typeHandlers><typeHandler handler="com.example.JsonTypeHandler"/>
</typeHandlers>

在 Mapper 中使用

<resultMap id="userResultMap" type="User"><result column="json_data" property="data" typeHandler="com.example.JsonTypeHandler"/>
</resultMap>

三、类型别名(TypeAlias)

1. 功能
  • 简化配置:为长类名定义短别名,避免 XML 中重复书写全限定类名。
  • 提升可读性:例如将 java.util.List 别名为 list
2. 使用方式

方式一:XML 配置

<!-- mybatis-config.xml -->
<typeAliases><typeAlias type="com.example.User" alias="User"/><package name="com.example.dto"/> <!-- 自动扫描包下所有类,别名为首字母小写的类名 -->
</typeAliases>

方式二:注解配置

@Alias("User")  // 在类上添加注解
public class User { ... }

在 Mapper 中使用别名

<select id="getUser" resultType="User">  <!-- 直接使用别名 -->SELECT * FROM users WHERE id = #{id}
</select>

四、类型处理器注册表(TypeHandlerRegistry)

1. 职责
  • 全局管理 TypeHandler:维护 Java类型 ↔ JDBC类型 ↔ TypeHandler 的映射关系。
  • 自动发现机制:通过 <typeHandlers> 配置或扫描包路径注册处理器。
2. 优先级规则

当多个 TypeHandler 可处理同一类型时,按以下顺序选择:

  1. 显式指定 typeHandler 属性的处理器。
  2. 注解 @MappedTypes@MappedJdbcTypes 精确匹配的处理器。
  3. 默认注册的处理器(如 StringTypeHandler)。

五、常见应用场景

1. 处理枚举类型
  • 按名称存储(默认):使用 EnumTypeHandler,将枚举的 name() 存入数据库。
  • 按序数存储:使用 EnumOrdinalTypeHandler,将枚举的 ordinal() 存入数据库。
  • 自定义存储逻辑:实现 TypeHandler 接口,例如将枚举转换为特定代码值。
2. 处理复杂类型
  • JSON 字段:如上述 JsonTypeHandler 示例。
  • 加密字段:自定义处理器,在写入时加密、读取时解密敏感数据(如手机号、身份证号)。
3. 处理集合类型
  • 默认支持:MyBatis 内置 ListTypeHandlerMapTypeHandler,但通常直接通过 resultMap 映射集合属性,无需手动处理。

六、最佳实践

1. 合理使用类型别名
  • 统一管理:在 mybatis-config.xml 中集中定义别名,避免分散配置。
  • 避免冲突:确保不同包下的类别名唯一,或直接使用全限定类名。
2. 自定义 TypeHandler 的注意事项
  • 线程安全:确保 TypeHandler 无状态或使用线程安全的数据结构(如上述 ObjectMapper 可复用)。
  • 异常处理:捕获并转换异常为 SQLException,避免框架层面崩溃。
3. 性能优化
  • 缓存复杂对象:若频繁解析 JSON 或加密数据,可添加缓存层(如 ConcurrentHashMap)。
  • 避免过度自定义:优先使用 MyBatis 内置处理器,减少不必要的复杂性。

七、总结

MyBatis 的类型系统通过 类型处理器类型别名 等机制,屏蔽了 Java 对象与数据库类型之间的差异,使开发者能够专注于业务逻辑。通过合理使用内置功能并扩展自定义 TypeHandler,可以高效处理复杂数据类型,提升代码可维护性和灵活性。

http://www.xdnf.cn/news/265753.html

相关文章:

  • 基于51单片机和LCD1602、矩阵按键的小游戏《猜数字》
  • 【BLE】【nRF Connect】 精讲nRF Connect自动化测试套件(宏录制、XML脚本)
  • 大数据:数字时代的驱动力
  • 应用层自定义协议序列与反序列化
  • toLua笔记
  • 突破认知边界:神经符号AI的未来与元认知挑战
  • Vmware设置静态IP和主机访问
  • 用单目相机和apriltag二维码aruco实现单目定位
  • Go语言的优势与应用场景 -《Go语言实战指南》
  • 5月3日日记
  • 删除有序数组中的重复项 II
  • 【2025软考高级架构师】——计算机网络(9)
  • FPGA DDR4多通道管理控制器设计
  • 自己部署后端,浏览器显示久久未响应
  • 模型测试报错:有2张显卡但cuda.device_count()显示GPU卡数量只有一张
  • 计算机组成原理实验(7) 堆指令部件模块实验
  • C++STL之vector
  • 2018-2020年 北京大学县域数字乡村指数
  • 深度学习:AI 机器人时代
  • Sharding-JDBC分库分表中的热点数据分布不均匀问题及解决方案
  • 第一节:OpenCV 基础入门-简介与环境搭建
  • AI开源框架对比:PyTorch vs TensorFlow vs PaddlePaddle
  • Java 入门篇
  • MySQL--索引入门
  • SQL笔记——左连接、右连接、内连接
  • Java线程创建与并发管理
  • 【第十六届蓝桥杯省赛】比赛心得与经验分享(PythonA 组)
  • 有机玻璃材质数据采集活性炭吸附气体中二氧化硫实验装置
  • Go小技巧易错点100例(二十七)
  • 数据分析与可视化实战:从鸢尾花到乳腺癌数据集