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 序列化器)。