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

