MyBatis 的 類型系統(Type System) 是框架處理 Java 類型與數據庫類型之間映射的核心模塊,它通過 類型處理器(TypeHandler)、類型別名(TypeAlias) 和 類型轉換器 等機制,實現了數據庫字段與 Java 對象屬性的無縫轉換。以下是其核心功能、使用場景及實現原理的詳解:
一、類型系統的核心組件
組件 | 作用 |
| 處理 Java 類型與 JDBC 類型之間的轉換(如 |
| 為 Java 類型定義別名,簡化 XML 配置中的類型名稱。 |
| 全局注冊所有 |
| 創建結果集映射的 Java 對象實例(如 POJO、集合等)。 |
二、類型處理器(TypeHandler)
1. 功能與職責
- 雙向轉換:
-
- 寫入數據庫:將 Java 對象屬性轉換為 JDBC 參數(
PreparedStatement.setXxx
)。 - 讀取數據庫:將 JDBC 結果集(
ResultSet.getXxx
)轉換為 Java 對象屬性。
- 寫入數據庫:將 Java 對象屬性轉換為 JDBC 參數(
- 支持復雜類型:
-
- 枚舉、集合、自定義對象、JSON 字符串等。
2. 內置 TypeHandler
MyBatis 默認注冊了常見類型的處理器,例如:
Java 類型 | JDBC 類型 | 對應 TypeHandler |
|
|
|
|
|
|
|
|
|
|
|
|
枚舉類 |
|
|
枚舉類(按序數存儲) |
|
|
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 可處理同一類型時,按以下順序選擇:
- 顯式指定
typeHandler
屬性的處理器。 - 注解
@MappedTypes
和@MappedJdbcTypes
精確匹配的處理器。 - 默認注冊的處理器(如
StringTypeHandler
)。
五、常見應用場景
1. 處理枚舉類型
- 按名稱存儲(默認):使用
EnumTypeHandler
,將枚舉的name()
存入數據庫。 - 按序數存儲:使用
EnumOrdinalTypeHandler
,將枚舉的ordinal()
存入數據庫。 - 自定義存儲邏輯:實現
TypeHandler
接口,例如將枚舉轉換為特定代碼值。
2. 處理復雜類型
- JSON 字段:如上述
JsonTypeHandler
示例。 - 加密字段:自定義處理器,在寫入時加密、讀取時解密敏感數據(如手機號、身份證號)。
3. 處理集合類型
- 默認支持:MyBatis 內置
ListTypeHandler
、MapTypeHandler
,但通常直接通過resultMap
映射集合屬性,無需手動處理。
六、最佳實踐
1. 合理使用類型別名
- 統一管理:在
mybatis-config.xml
中集中定義別名,避免分散配置。 - 避免沖突:確保不同包下的類別名唯一,或直接使用全限定類名。
2. 自定義 TypeHandler 的注意事項
- 線程安全:確保
TypeHandler
無狀態或使用線程安全的數據結構(如上述ObjectMapper
可復用)。 - 異常處理:捕獲并轉換異常為
SQLException
,避免框架層面崩潰。
3. 性能優化
- 緩存復雜對象:若頻繁解析 JSON 或加密數據,可添加緩存層(如
ConcurrentHashMap
)。 - 避免過度自定義:優先使用 MyBatis 內置處理器,減少不必要的復雜性。
七、總結
MyBatis 的類型系統通過 類型處理器 和 類型別名 等機制,屏蔽了 Java 對象與數據庫類型之間的差異,使開發者能夠專注于業務邏輯。通過合理使用內置功能并擴展自定義 TypeHandler
,可以高效處理復雜數據類型,提升代碼可維護性和靈活性。