mybatis的typeHandler 作用
2026/7/24 5:39:10 网站建设 项目流程

在 MyBatis 中,`TypeHandler`(类型处理器)扮演着 **“翻译官”** 或 **“桥梁”** 的角色。

它的核心作用是:**在 Java 数据类型和 JDBC 数据库数据类型之间进行相互转换。**

因为 Java 的类型(如 `String`, `Date`, `Enum`, 自定义对象)和数据库的类型(如 `VARCHAR`, `TIMESTAMP`, `INT`)并不总是完全一一对应的,`TypeHandler` 就是为了解决这种类型不匹配的问题而存在的。

---

### 一、 `TypeHandler` 的两个核心工作方向

`TypeHandler` 的工作是双向的,主要分为“设置参数”和“获取结果”两个过程:

1. **设置参数(Java -> 数据库)**:
* 当你执行 `INSERT` 或 `UPDATE` 操作时,MyBatis 需要将 Java 对象的属性值设置到 SQL 语句的占位符(`?`)中。
* 此时,`TypeHandler` 负责将 **Java 类型** 转换为 **JDBC 类型**,并调用 `PreparedStatement.setXXX()` 方法存入数据库。
2. **获取结果(数据库 -> Java)**:
* 当你执行 `SELECT` 操作时,MyBatis 需要从数据库的查询结果集(`ResultSet`)中读取数据,并赋值给 Java 对象。
* 此时,`TypeHandler` 负责将 **JDBC 类型** 转换为 **Java 类型**,并调用 `ResultSet.getXXX()` 方法获取数据。

---

### 二、 为什么需要自定义 `TypeHandler`?(常见应用场景)

MyBatis 内部已经默认注册了大量的 `TypeHandler`(如 `StringTypeHandler`, `IntegerTypeHandler`, `DateTypeHandler` 等),能处理 90% 以上的常规映射。**但在以下场景中,你需要自定义 `TypeHandler`:**

#### 1. 数据库存储 JSON,Java 使用对象/集合
* **场景**:数据库字段是 `VARCHAR` 或 `JSON` 类型,存的是 `{"name":"张三","age":18}`。但在 Java 中,你希望直接映射为一个 `UserDetail` 对象或 `List<String>`。
* **解决**:自定义 `TypeHandler`,在入库时用 Jackson/Fastjson 将对象序列化为 JSON 字符串,出库时反序列化为 Java 对象。

#### 2. 枚举类型(Enum)的特殊映射
* **场景**:数据库里存的是枚举的 `code`(如数字 `1` 或字符串 `"MALE"`),但 Java 里使用的是枚举类 `GenderEnum.MALE`。
* **解决**:MyBatis 默认使用枚举的 `name()` 或 `ordinal()` 进行转换。如果数据库存的是自定义的 `code` 属性,就需要自定义 `TypeHandler` 来根据 `code` 查找对应的枚举实例。

#### 3. 数据的加密与解密
* **场景**:数据库中的手机号、身份证号、密码等敏感信息是**加密存储**的(如 AES 密文),但 Java 业务代码中需要使用的是**明文**。
* **解决**:自定义 `TypeHandler`,在 `setNonNullParameter` 时进行加密,在 `getNullableResult` 时进行解密。对业务代码完全透明。

#### 4. 复杂字符串与集合的转换
* **场景**:数据库存的是逗号分隔的字符串 `"1,2,3"`,Java 中希望映射为 `List<Integer>` 或 `Integer[]`。
* **解决**:自定义 `TypeHandler`,入库时 `StringUtils.join()`,出库时 `StringUtils.split()`。

---

### 三、 如何自定义 `TypeHandler`?

在实际开发中,我们通常不会直接实现 `TypeHandler` 接口(因为方法太多),而是**继承 `BaseTypeHandler<T>`**,它帮我们处理了空值(null)的判断逻辑。

#### 1. 编写自定义 TypeHandler
以 **“数据库存 JSON 字符串,Java 存 Object 对象”** 为例:

```java
// 指定该 Handler 处理的 Java 类型和 JDBC 类型
@MappedTypes(Object.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JsonTypeHandler<T> extends BaseTypeHandler<T> {

private Class<T> clazz;

public JsonTypeHandler(Class<T> clazz) {
if (clazz == null) throw new IllegalArgumentException("Type argument cannot be null");
this.clazz = clazz;
}

// 1. Java -> DB (设置参数)
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
// 将 Java 对象转为 JSON 字符串存入数据库
ps.setString(i, JSON.toJSONString(parameter));
}

// 2. DB -> Java (根据列名获取结果)
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return convertJsonToObject(json);
}

// 2. DB -> Java (根据列索引获取结果)
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return convertJsonToObject(json);
}

// 2. DB -> Java (存储过程获取结果)
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return convertJsonToObject(json);
}

private T convertJsonToObject(String json) {
if (json == null || json.isEmpty()) return null;
return JSON.parseObject(json, clazz); // 使用 Fastjson 或 Jackson 反序列化
}
}
```

#### 2. 注册和使用 TypeHandler

写好之后,需要告诉 MyBatis 去使用它。有两种主要方式:

**方式一:全局自动扫描(推荐)**
在 `application.yml` (Spring Boot) 或 `mybatis-config.xml` 中配置包扫描,MyBatis 启动时会自动注册该包下的所有 `TypeHandler`。
```yaml
mybatis:
type-handlers-package: com.yourproject.mybatis.handler
```

**方式二:在 Mapper XML 中显式指定**
如果不想全局生效,可以在具体的 SQL 映射中强制指定使用哪个 `TypeHandler`。
```xml
<!-- 插入/更新时指定 -->
INSERT INTO user (id, extra_info)
VALUES (#{id}, #{extraInfo, typeHandler=com.yourproject.mybatis.handler.JsonTypeHandler})

<!-- 查询结果映射时指定 -->
<resultMap id="userMap" type="User">
<result column="extra_info" property="extraInfo"
typeHandler="com.yourproject.mybatis.handler.JsonTypeHandler"/>
</resultMap>
```

### 四、 总结

* **本质**:`TypeHandler` 是 Java 类型与 JDBC 类型之间的转换器。
* **默认行为**:MyBatis 内置了数十种常用的 `TypeHandler`,绝大多数基础类型无需手动干预。
* **核心价值**:当遇到 **JSON 映射、枚举特殊映射、数据加解密、格式特殊转换** 等 MyBatis 默认无法处理的场景时,通过自定义 `TypeHandler` 可以在**不侵入业务代码**的前提下,优雅地解决数据持久化问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询