【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.mzph.cn/pingmian/79254.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新华三H3CNE网络工程师认证—动态NAT

静态NAT严格地一对一进行地址映射&#xff0c;这就导致即便内网主机长时间离线或者不发送数据时&#xff0c;与之对应的共有地址也处于使用状态。为了避免地址浪费&#xff0c;动态NAT提出了地址池的概念&#xff1a;所有可用的共用地址组成地址池。 当内部主机访问外部网络时临…

华为OD机试真题 Java 实现【水库蓄水问题】

前言 博主刷的华为机考题&#xff0c;代码仅供参考&#xff0c;因为没有后台数据&#xff0c;可能有没考虑到的情况 如果感觉对你有帮助&#xff0c;请点点关注点点赞吧&#xff0c;谢谢你&#xff01; 题目描述 思路 1. 其实就是找一个最大的水坑&#xff0c;两个…

【Linux】Petalinux驱动开发基础

基于Petalinux做Linux驱动开发。 部分图片和经验来源于网络,若有侵权麻烦联系我删除,主要是做笔记的时候忘记写来源了,做完笔记很久才写博客。 专栏目录:记录自己的嵌入式学习之路-CSDN博客 目录 1 一个完整的Linux系统(针对Zynq) 1.1 PS部分 1.2 PL部分(若…

JAVA刷题记录: 递归,搜索与回溯

专题一 递归 面试题 08.06. 汉诺塔问题 - 力扣&#xff08;LeetCode&#xff09; class Solution {public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {dfs(A, B, C, A.size());}public void dfs(List<Integer> a, List<In…

YOLOv11改进:利用RT-DETR主干网络PPHGNetV2助力轻量化目标检测

这里写自定义目录标题 YOLOv11改进&#xff1a;利用RT-DETR主干网络PPHGNetV2助力轻量化目标检测1. 介绍2. 引言3. 技术背景3.1 YOLOv11概述3.2 RT-DETR与PPHGNetV23.3 相关工作 4. 应用使用场景5. 详细代码实现5.1 环境准备5.2 PPHGNetV2主干网络实现5.3 YOLOv11与PPHGNetV2集…

WPF之Button控件详解

文章目录 1. 引言2. Button控件基础Button类定义 3. Button控件的核心属性3.1 Content属性3.2 IsDefault属性3.3 IsCancel属性3.4 其他常用属性 4. 按钮样式与模板自定义4.1 简单样式设置4.2 使用Style对象4.3 触发器使用4.4 使用ControlTemplate完全自定义4.5 按钮视觉状态 5.…

【Java】2025 年 Java 学习路线:从入门到精通

文章目录 一、Java基础阶段(4-8周)1. 开发环境搭建2. 核心语法基础3. 面向对象编程(OOP)4. 核心类库二、Java进阶阶段(6-10周)1. JVM深度理解2. 并发编程3. 新特性掌握4. 设计模式三、开发框架与中间件(8-12周)1. Spring生态2. 持久层框架3. 常用中间件四、项目实战阶段…

虚幻引擎入门笔记

【虚幻5】UE5新手入门尝试 虚幻引擎的基础设置 1.验证-当文件误删的时候&#xff0c;对其进行验证&#xff0c;可以恢复。 2.虚幻引擎极其强大&#xff0c;可以实现多种复合技能&#xff0c;所在创建项目页面可以看见不只是创建游戏的项目 3.更改虚幻引擎默认的缓存地址。有些…

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】1.1 数据库核心概念与PostgreSQL技术优势

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 深度解析PostgreSQL核心架构与技术优势&#xff1a;从数据库原理到实战场景1.1 数据库核心概念与PostgreSQL技术优势1.1.1 关系型数据库核心架构解析1.1.1.1 数据库系统的底…

详解SLAM中的李群和李代数(上)

1 概述 最近阅读高翔大神的《视觉SLAM十四讲》这本书&#xff0c;感觉整本书写的非常的平实&#xff0c;用非常接地气的语言毫无保留的介绍了视觉SLAM的相关知识&#xff0c;非常值得一读。不过&#xff0c;在第4章出现的李群和李代数的相关概念就有点令人难以费解了。其实这段…

libevent库详解:高性能异步IO的利器

目录 一、libevent 简介 主要特点&#xff1a; 二、事件模型原理 1. event_base 2. event 3. evconnlistener&#xff08;TCP监听器&#xff09; 4. bufferevent 简化流程如下&#xff1a; 三、libevent 使用示例 1. 创建事件主循环 2. 创建监听器&#xff08;TCP&a…

从 “零” 做个开源音乐软件“SteadyBeat”吧!<1> 准备

换换脑子&#xff0c;做个音乐软件&#xff0c;根据调性、和弦走向&#xff08;情感&#xff09;、节拍、速度等需求&#xff0c;结合AI和一众工具&#xff0c;自动生成伴奏、Solo等&#xff0c;有点像库乐队&#xff01;自己平时也用得着&#xff0c;暂时取名叫《SteadyBeat》…

npm error code CERT_HAS_EXPIRED

npm error code CERT_HAS_EXPIRED 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社区主理人 擅长.net、C、python开发&#xff0c; 如果遇到技术问题&#xff0c;即可私…

数字世界的“私人车道“:网络切片如何用Python搭建专属通信高速路?

数字世界的"私人车道"&#xff1a;网络切片如何用Python搭建专属通信高速路&#xff1f; 2024年6月&#xff0c;中国移动宣布在浙江某智能工厂完成全球首个"5G工业网络切片"规模商用——这条为生产线定制的"数字专属车道"&#xff0c;将设备控制…

VSCode Verilog编辑仿真环境搭建

VSCode Verilog环境搭建 下载Iverilog安装Iverilog验证安装VS Code安装插件 下载Iverilog 官网下载Iverilog 安装Iverilog 一定要勾选这两项 建议勾选这两项 验证安装 运行Windows PowerShell输入命令&#xff1a;iverilog输入命令&#xff1a;Get-Command gtkwave …

C++ - 数据容器之 list(创建与初始化、元素访问、容量判断、元素遍历、添加元素、删除元素)

一、创建与初始化 引入 <list> 并使用 std 命名空间 #include <list>using namespace std;创建一个空 list list<int> my_list;创建一个包含 5 个元素&#xff0c;每个元素初始化为 0 的 list list<int> my_list(5);创建一个包含 5 个元素&#xf…

自动化测试项目1 --- 唠嗑星球 [软件测试实战 Java 篇]

目录 项目介绍 项目源码库地址 项目功能测试 1.自动化实施步骤 1.1 编写测试用例 1.2 自动化测试脚本开发 1.2.1 配置相关环境, 添加相关依赖 1.2.2 相关代码编写 2. 自动化功能测试总结 2.1 弹窗的解决相关问题 2.2 断言的使用和说明 2.3 重新登录问题 项目性能…

Codeforces Round 1022 (Div. 2)(ABC)

A. Permutation Warm-Up 翻译&#xff1a; 对于长度为 n 的排列 p&#xff0c;我们定义函数&#xff1a; 给你一个数 n。你需要计算函数 f(p) 在考虑从 1 到 n 的所有可能的数字排列时&#xff0c;可以取多少个不同的值。 思路&#xff1a; 按序排列时和为0&…

数据结构------C语言经典题目(6)

1.数据结构都学了些什么&#xff1f; 1.基本数据类型 算数类型&#xff1a; char&#xff08;字符&#xff09;、int&#xff08;整数&#xff09;、float&#xff08;单精度浮点数&#xff09;、double&#xff08;双精度浮点数&#xff09;等。 枚举类型&#xff1a; enum…

如何封装一个线程安全、可复用的 HBase 查询模板

目录 一、前言&#xff1a;原生 HBase 查询的痛点 &#xff08;一&#xff09;连接管理混乱&#xff0c;容易造成资源泄露 &#xff08;二&#xff09;查询逻辑重复&#xff0c;缺乏统一的模板 &#xff08;三&#xff09;多线程/高并发下的线程安全性隐患 &#xff08;四…