BaseTypeHandler用法-笔记
1.BaseTypeHandler简介
org.apache.ibatis.type.BaseTypeHandler
是 MyBatis 提供的一个抽象类,通过继承该类并实现关键方法,可用于实现 Java 类型 与 JDBC 类型 之间的双向转换。当数据库字段类型与 Java 对象属性类型不一致时(如:枚举类型、自定义对象、JSON 字段等),可以通过自定义 BaseTypeHandler
实现灵活的数据类型映射。
1.1 核心方法
BaseTypeHandler<T>
是泛型类,其中 T
表示 Java 类型。需要实现以下 4 个核心方法:
方法 | 作用 |
---|---|
void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) | 将 Java 类型转换为 JDBC 类型,设置到 SQL 语句中 |
T getNullableResult(ResultSet rs, String columnName) | 从 ResultSet 中通过列名获取 Java 类型值 |
T getNullableResult(ResultSet rs, int columnIndex) | 从 ResultSet 中通过列索引获取 Java 类型值 |
T getNullableResult(CallableStatement cs, int columnIndex) | 从存储过程结果中通过列索引获取 Java 类型值 |
1.2 典型使用场景
- 枚举类型映射:将数据库中的字符串或整数映射为 Java 枚举。
- 复杂对象映射:将 JSON 字符串转换为 Java 对象(如
List<T>
或自定义类)。 - 特殊类型转换:将数据库中的
DATE
/TIMESTAMP
映射为LocalDateTime
等。
2. 使用示例
2.1 枚举类型转换
将自定义的枚举类型与数据库里的String类型做自动转换。
step1.定义枚举类
public enum Status {ACTIVE("active"),INACTIVE("inactive");private final String code;Status(String code) {this.code = code;}public String getCode() {return code;}public static Status fromCode(String code) {for (Status status : values()) {if (status.code.equals(code)) {return status;}}throw new IllegalArgumentException("Invalid code: " + code);}
}
step2.自定义 TypeHandler,用于将枚举 Status 类和数据库中的String类做转换
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class StatusTypeHandler extends BaseTypeHandler<Status> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Status parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, parameter.getCode());}@Overridepublic Status getNullableResult(ResultSet rs, String columnName) throws SQLException {String code = rs.getString(columnName);return code == null ? null : Status.fromCode(code);}@Overridepublic Status getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String code = rs.getString(columnIndex);return code == null ? null : Status.fromCode(code);}@Overridepublic Status getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String code = cs.getString(columnIndex);return code == null ? null : Status.fromCode(code);}
}
step3. 在XML映射文件中使用
- status在数据库users表里是一个String类型字符串;在 User类里是一个 Status 枚举类型对象
- 经过StatusTypeHandler处理后,可以将数据库的String类型映射为User里的Status枚举类型
<!-- UserMapper.xml -->
<resultMap id="userResultMap" type="User"><result column="status" property="status" typeHandler="com.example.StatusTypeHandler"/>
</resultMap><select id="selectUser" resultMap="userResultMap">SELECT * FROM users WHERE id = #{id}
</select>
2.2 JSON类型转换
将JSONObject类型与数据库里的String类型做转换:
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSONObject;public class JSONObjectTypeHandler extends BaseTypeHandler<JSONObject> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType)throws SQLException {ps.setString(i, parameter == null ? "{}" : parameter.toJSONString());}@Overridepublic JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException {String json = rs.getString(columnName);return StringUtils.isBlank(json) ? new JSONObject() : JSONObject.parseObject(json);}@Overridepublic JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String json = rs.getString(columnIndex);return StringUtils.isBlank(json) ? new JSONObject() : JSONObject.parseObject(json);}@Overridepublic JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String json = cs.getString(columnIndex);return StringUtils.isBlank(json) ? new JSONObject() : JSONObject.parseObject(json);}
}
2.3 注意事项
- 空值处理:在
getNullableResult
中需判断null
,避免 NPE。 - 线程安全:避免在
TypeHandler
中使用可变成员变量。 - 性能优化:避免在转换过程中频繁创建对象(如 JSON 序列化器)。