MyBatis 管理和查找TypeHandler的方法
MyBatis 通過 TypeHandlerRegistry
組件來集中 管理和查找 TypeHandler。 TypeHandler
是 MyBatis 中用于 處理 Java 類型和 JDBC 類型之間轉(zhuǎn)換 的重要組件。 MyBatis 需要管理大量的 TypeHandler,并能夠根據(jù)需要快速找到合適的 TypeHandler 來進行類型轉(zhuǎn)換。
1. TypeHandlerRegistry 的作用:TypeHandler 的注冊中心
TypeHandlerRegistry
可以被理解為 MyBatis 中 TypeHandler 的注冊中心 或 TypeHandler 的倉庫。 它的核心作用是:
- 注冊 TypeHandler: 負責(zé)注冊各種 TypeHandler 到 MyBatis 系統(tǒng)中。 TypeHandler 可以是 MyBatis 內(nèi)置的,也可以是用戶自定義的。
- 存儲 TypeHandler: 內(nèi)部維護一個數(shù)據(jù)結(jié)構(gòu) (實際上是多個
Map
) 來存儲已注冊的 TypeHandler,并按照不同的維度進行組織,方便查找。 - 查找 TypeHandler: 提供 API 方法,允許 MyBatis 在運行時根據(jù) Java 類型和/或 JDBC 類型,快速查找并獲取合適的 TypeHandler 實例。
2. TypeHandlerRegistry 如何管理 TypeHandler:內(nèi)部存儲結(jié)構(gòu)
TypeHandlerRegistry
內(nèi)部使用多個 Map
來存儲 TypeHandler,以便根據(jù)不同的查找條件進行高效檢索。 主要的存儲結(jié)構(gòu)包括:
KNOWN_TYPE_HANDLERS
(Map<JdbcType, TypeHandler<?>>):
- Key: JdbcType 枚舉值,代表 JDBC 類型。
- Value: TypeHandler<?> 實例。
- 作用: 根據(jù) JDBC 類型查找 TypeHandler。 例如,當 MyBatis 需要處理 VARCHAR 類型的參數(shù)或結(jié)果時,會使用 KNOWN_TYPE_HANDLERS 查找與 JdbcType.VARCHAR 關(guān)聯(lián)的 TypeHandler。
TYPE_HANDLER_MAP
(Map<Type, Map<JdbcType, TypeHandler<?>>>):
- Outer Key:
Type
對象,代表 Java 類型。 - Inner Key:
JdbcType
枚舉值,代表 JDBC 類型 (可以為null
,表示不區(qū)分 JDBC 類型)。 - Value:
TypeHandler<?>
實例。 - 作用: 根據(jù) Java 類型和 JDBC 類型查找 TypeHandler。 這是最主要的 TypeHandler 存儲和查找結(jié)構(gòu)。 MyBatis 會優(yōu)先使用
TYPE_HANDLER_MAP
進行查找。 - 層級結(jié)構(gòu):
TYPE_HANDLER_MAP
是一個兩層嵌套的Map
。 外層Map
的 Key 是 Java 類型,內(nèi)層Map
的 Key 是 JDBC 類型。 這種結(jié)構(gòu)允許根據(jù) Java 類型和 JDBC 類型的組合來精確查找 TypeHandler。
ALL_TYPE_HANDLERS_MAP
(Map<Class<?>, TypeHandler<?>>):
- Key:
Class<?>
對象,代表 TypeHandler 的 Class 類型。 - Value:
TypeHandler<?>
實例。 - 作用: 根據(jù) TypeHandler 的 Class 類型查找 TypeHandler 實例。 主要用于通過
TypeHandlerRegistry.getTypeHandler(Class<? extends TypeHandler> handlerType)
方法直接根據(jù) TypeHandler 類型查找實例。
3. TypeHandler 的注冊方式:
TypeHandler 可以通過多種方式注冊到 TypeHandlerRegistry
中:
3.1. XML 配置文件 (mybatis-config.xml):
<typeHandlers>
元素和 <typeHandler>
子元素: 在 mybatis-config.xml
文件中使用 <typeHandlers>
元素和 <typeHandler>
子元素來注冊 TypeHandler。
<typeHandlers> <typeHandler javaType="java.lang.String" jdbcType="VARCHAR" handler="com.example.typehandler.MyStringTypeHandler"/> <typeHandler package="com.example.typehandler.package"/> <!-- 掃描包注冊 TypeHandler --> </typeHandlers>
javaType
屬性 (可選): 指定 TypeHandler 處理的 Java 類型。 可以指定多個 Java 類型,用逗號分隔。jdbcType
屬性 (可選): 指定 TypeHandler 處理的 JDBC 類型。 可以指定多個 JDBC 類型,用逗號分隔。handler
屬性: 指定 TypeHandler 實現(xiàn)類的全限定名。<typeHandler package="...">
: 指定包名,MyBatis 會掃描指定包下的所有 TypeHandler,并自動注冊。
XMLConfigBuilder
解析 <typeHandlers>
元素時,會將配置的 TypeHandler 注冊到 Configuration
對象的 typeHandlerRegistry
中。
3.2. Java 代碼配置 (Configuration 對象):
Configuration.getTypeHandlerRegistry().register(...)
方法: 可以通過 Configuration
對象的 getTypeHandlerRegistry()
方法獲取 TypeHandlerRegistry
實例,然后使用 register()
方法手動注冊 TypeHandler。
Configuration configuration = new Configuration(); TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); typeHandlerRegistry.register(String.class, JdbcType.VARCHAR, new MyStringTypeHandler()); // 注冊指定 Java 類型和 JDBC 類型的 TypeHandler typeHandlerRegistry.register(MyEnumTypeHandler.class); // 注冊 TypeHandler,不指定 Java 類型和 JDBC 類型 (MyEnumTypeHandler 需要標注 @MappedTypes 和 @MappedJdbcTypes) typeHandlerRegistry.register(new MyDefaultTypeHandler()); // 注冊 TypeHandler 實例,不指定 Java 類型和 JDBC 類型 (MyDefaultTypeHandler 需要標注 @MappedTypes 和 @MappedJdbcTypes)
register(TypeHandler<?> typeHandler)
: 注冊 TypeHandler 實例。TypeHandler 類需要使用@MappedTypes
和@MappedJdbcTypes
注解指定它處理的 Java 類型和 JDBC 類型。register(Class<?> javaType, TypeHandler<?> typeHandler)
: 注冊指定 Java 類型的 TypeHandler 實例。register(JdbcType jdbcType, TypeHandler<?> typeHandler)
: 注冊指定 JDBC 類型的 TypeHandler 實例。register(Class<?> javaType, JdbcType jdbcType, TypeHandler<?> typeHandler)
: 注冊指定 Java 類型和 JDBC 類型的 TypeHandler 實例。register(String typeHandlerName)
: 根據(jù) TypeHandler 的別名注冊 TypeHandler (別名需要在<typeAliases>
中定義)。
3.3. 自動掃描包 (<typeHandlers package="...">):
- 通過在
<typeHandlers>
元素中使用<typeHandler package="...">
子元素,可以指定包名。 MyBatis 會 自動掃描指定包及其子包下的所有 TypeHandler 實現(xiàn)類,并將它們注冊到TypeHandlerRegistry
中。 - TypeHandler 類需要使用
@MappedTypes
和@MappedJdbcTypes
注解來聲明它處理的 Java 類型和 JDBC 類型。
3.4. MyBatis 內(nèi)置的 TypeHandler:
- MyBatis 框架內(nèi)置了大量的常用 TypeHandler,用于處理 Java 基本類型、常用 Java 類型 (例如 String, Date, Enum) 和 JDBC 類型之間的轉(zhuǎn)換。
- 這些內(nèi)置的 TypeHandler 在
TypeHandlerRegistry
初始化時會被自動注冊,無需顯式配置。 例如:StringTypeHandler
,IntegerTypeHandler
,DateTypeHandler
,EnumTypeHandler
等。
4. TypeHandlerRegistry 如何查找 TypeHandler:查找策略
當 MyBatis 需要進行類型轉(zhuǎn)換時 (例如設(shè)置 PreparedStatement 參數(shù),獲取 ResultSet 結(jié)果),會通過 TypeHandlerRegistry
查找合適的 TypeHandler。 TypeHandlerRegistry
的查找策略如下 (優(yōu)先級從高到低):
4.1. 精確匹配 Java 類型和 JDBC 類型:
MyBatis 會首先嘗試 根據(jù) Java 類型和 JDBC 類型的精確組合 在 TYPE_HANDLER_MAP
中查找 TypeHandler。 這是最精確的查找方式,如果找到,則直接使用該 TypeHandler。
4.2. 匹配 Java 類型,忽略 JDBC 類型:
如果精確匹配 Java 類型和 JDBC 類型沒有找到 TypeHandler,MyBatis 會嘗試 只根據(jù) Java 類型 在 TYPE_HANDLER_MAP
中查找 TypeHandler (JDBC 類型設(shè)置為 null
)。 這種方式適用于某些 TypeHandler 只需要根據(jù) Java 類型進行處理,而不需要區(qū)分 JDBC 類型的情況。
4.3. 根據(jù) JDBC 類型查找:
如果根據(jù) Java 類型和 JDBC 類型都無法找到合適的 TypeHandler,MyBatis 會嘗試 根據(jù) JDBC 類型 在 KNOWN_TYPE_HANDLERS
中查找 TypeHandler。 這種方式適用于某些通用的 JDBC 類型處理場景,例如處理所有 VARCHAR
類型的數(shù)據(jù),可以使用與 JdbcType.VARCHAR
關(guān)聯(lián)的 TypeHandler。
4.4. 類型繼承關(guān)系查找 (Type Hierarchy):
如果以上方式都無法找到合適的 TypeHandler,MyBatis 還會 考慮 Java 類型的繼承關(guān)系。 例如,如果查找 List
類型的 TypeHandler 失敗,MyBatis 會嘗試查找 Collection
, Iterable
, Object
等父類型或接口的 TypeHandler。 這種方式可以提高 TypeHandler 的通用性。
4.5. 默認 TypeHandler (Default TypeHandler):
如果經(jīng)過上述所有查找策略都無法找到合適的 TypeHandler,MyBatis 會 使用默認的 ObjectTypeHandler
(或其他默認 TypeHandler) 進行處理。 ObjectTypeHandler
可以處理 Object
類型的數(shù)據(jù),但可能會丟失類型信息,性能也可能較低。
5. 關(guān)鍵組件和類:
TypeHandlerRegistry
: TypeHandler 注冊中心,負責(zé)管理和查找 TypeHandler。TypeHandler
接口: 所有 TypeHandler 實現(xiàn)類都需要實現(xiàn)的接口,定義了類型轉(zhuǎn)換的方法 (setParameter()
,getResult()
).Configuration
對象:TypeHandlerRegistry
實例存儲在Configuration
對象中。XMLConfigBuilder
: 在解析mybatis-config.xml
文件時,XMLConfigBuilder
負責(zé)解析<typeHandlers>
元素,并將配置的 TypeHandler 注冊到Configuration
對象的typeHandlerRegistry
中。JdbcType
枚舉: 定義了 JDBC 類型常量。Type
接口 (Java Reflection API): 表示 Java 類型。
總結(jié)
TypeHandlerRegistry
的作用和 TypeHandler 的管理和查找機制:TypeHandlerRegistry
是 MyBatis 中 TypeHandler 的注冊中心,負責(zé)管理和維護所有已注冊的 TypeHandler。TypeHandler 可以通過 XML 配置、Java 代碼配置、自動掃描包和 MyBatis 內(nèi)置等多種方式注冊到TypeHandlerRegistry
中。TypeHandlerRegistry
使用多層Map
結(jié)構(gòu)存儲 TypeHandler,并提供高效的查找策略,可以根據(jù) Java 類型、JDBC 類型和類型繼承關(guān)系等條件查找合適的 TypeHandler。MyBatis 在運行時需要進行類型轉(zhuǎn)換時,會委托TypeHandlerRegistry
查找合適的 TypeHandler,并使用找到的 TypeHandler 進行類型轉(zhuǎn)換操作。TypeHandlerRegistry
的管理和查找機制保證了 MyBatis 能夠靈活、高效地處理各種 Java 類型和 JDBC 類型之間的轉(zhuǎn)換,實現(xiàn)了類型轉(zhuǎn)換的解耦和可擴展性。
到此這篇關(guān)于MyBatis 管理和查找TypeHandler的方法的文章就介紹到這了,更多相關(guān)MyBatis 查找TypeHandler內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis Mapper XML中比較操作符轉(zhuǎn)義問題解決
在使用MyBatis編寫Mapper XML時,有時會遇到比較操作符需要進行轉(zhuǎn)義的情況,本文主要介紹了MyBatis Mapper XML中比較操作符轉(zhuǎn)義問題解決,具有一定的參考價值,感興趣的可以了解一下2024-01-01spring boot task實現(xiàn)動態(tài)創(chuàng)建定時任務(wù)的方法
這篇文章主要介紹了spring boot task實現(xiàn)動態(tài)創(chuàng)建定時任務(wù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01解決MybatisPlus批量插入數(shù)據(jù)報錯:Error getting generated 
在使用MybatisPlus進行批量插入數(shù)據(jù)時遇到空指針異常錯誤,分析原因是由于主鍵生成策略導(dǎo)致的,嘗試通過設(shè)置useGeneratedKeys屬性解決問題,但因批量插入方法限制,該方法未能成功,最終通過自定義mapper方法實現(xiàn)批量插入,解決了問題2024-09-09