一文搞懂MyBatis中TypeHandler機制
前言
在進行項目開發(fā)時,我們經(jīng)常需要處理各種類型的數(shù)據(jù)轉(zhuǎn)換問題。特別是在使用數(shù)據(jù)庫時,常常會遇到需要將數(shù)據(jù)庫中的字符串字段與 Java 對象之間的復雜轉(zhuǎn)換。MyBatis 是一種流行的持久層框架,它提供了強大的數(shù)據(jù)訪問功能,同時與 Spring Boot 等微服務技術棧無縫集成。為了解決這一問題,MyBatis 提供了一個強大的機制——TypeHandler,其是 MyBatis 中一個用于處理 Java 類型和數(shù)據(jù)庫類型轉(zhuǎn)換的組件,它在 MyBatis 進行參數(shù)設置和結(jié)果映射時起著至關重要的作用。本文將詳細介紹TypeHandler 的使用方法,包括自定義 TypeHandler 的創(chuàng)建和注冊,以及在實際項目中的應用示例。
一、TypeHandler基礎
1.1 什么是 TypeHandler
在 MyBatis 中,TypeHandler (類型處理器)用于處理 Java 類型和 JDBC 類型之間的映射和轉(zhuǎn)換。例如,當數(shù)據(jù)庫中的字段是 JSON 字符串時,可以將其轉(zhuǎn)化為 Java 對象。每當 MyBatis 在執(zhí)行 SQL 操作時,都會使用 TypeHandler 來確保數(shù)據(jù)類型的正確轉(zhuǎn)換。在執(zhí)行 SQL 語句時,TypeHandler 將 Java 類型轉(zhuǎn)換為數(shù)據(jù)庫可以理解的類型。在讀取數(shù)據(jù)庫結(jié)果時,TypeHandler 將數(shù)據(jù)庫類型轉(zhuǎn)換回 Java 類型。這一過程對于開發(fā)者是透明的,由 MyBatis 框架內(nèi)部自動完成。
在 Mybatis 中給我們內(nèi)置提供了多種常用的類型處理器,這也就是為什么我們在日常開發(fā)過程中,不需要關心 Java 和數(shù)據(jù)庫之間的類型問題,Java 代碼和 MySQL 等數(shù)據(jù)庫之間卻能自動進行轉(zhuǎn)化的原因。

1.2 TypeHandler的工作原理
TypeHandler 在 MyBatis 中是一個核心概念,其工作原理主要涉及Java類型和JDBC類型之間的映射和轉(zhuǎn)換。
- 當MyBatis執(zhí)行一個預編譯的SQL語句(如INSERT、UPDATE等)時,它需要將Java對象中的屬性值設置到SQL語句中對應的占位符上。
- MyBatis會根據(jù)映射配置找到對應的TypeHandler實例,這個映射配置可以在MyBatis的配置文件或者Mapper的XML文件中定義。
- TypeHandler實例會接收到Java對象中的屬性值,并將其轉(zhuǎn)換為JDBC能夠識別的類型,這個轉(zhuǎn)換過程是根據(jù)Java類型和JDBC類型之間的映射關系來實現(xiàn)的。
- 轉(zhuǎn)換后的值會被設置到PreparedStatement對象中對應的占位符上,以便數(shù)據(jù)庫能夠正確解析和執(zhí)行SQL語句。
- 當數(shù)據(jù)庫執(zhí)行查詢操作并返回結(jié)果集時,MyBatis需要將結(jié)果集中的數(shù)據(jù)提取出來,并轉(zhuǎn)換為Java對象中的對應屬性類型。
- MyBatis會根據(jù)映射配置找到對應的TypeHandler實例。
- TypeHandler實例會從ResultSet對象中提取數(shù)據(jù),這個提取過程是根據(jù)數(shù)據(jù)庫字段和Java屬性之間的映射關系來實現(xiàn)的。
- 提取出的數(shù)據(jù)會被轉(zhuǎn)換為Java對象中的對應屬性類型,這個轉(zhuǎn)換過程同樣是根據(jù)Java類型和JDBC類型之間的映射關系來實現(xiàn)的。
- 轉(zhuǎn)換后的值會被設置到Java對象中對應的屬性上,以便應用程序能夠正確處理和使用這些數(shù)據(jù)。
二、TypeHandler 的應用
2.1 TypeHandler 接口
TypeHandler 是類型轉(zhuǎn)換器的頂層接口,其定義了類型轉(zhuǎn)換器應該具有的功能,通常用于 MyBatis 在設置預處理語句(PreparedStatement)中的參數(shù)時,完成 JAVA 類型到 JDBC 類型的轉(zhuǎn)換(通常用在#{}參數(shù)占位符中),以及在將查詢到的結(jié)果記錄映射到 JAVA 實體對象時,完成 JDBC 類型到 JAVA 類型的轉(zhuǎn)換(通常用在<result>標簽中)。以下是 TypeHandler 接口的一個基本概述:
public interface TypeHandler<T> {
/**
* 用于設置PreparedStatement對象的指定參數(shù)。
*
* @param ps 當前的PreparedStatement對象
* @param i 當前參數(shù)的位置
* @param parameter 當前參數(shù)的Java對象
* @param jdbcType 當前參數(shù)的數(shù)據(jù)庫類型
*/
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
/**
* 從結(jié)果集中根據(jù)列名獲取數(shù)據(jù)并轉(zhuǎn)換為 java 對象
*
* @param rs 當前的結(jié)果集
* @param columnName 當前的字段名稱
*/
T getResult(ResultSet rs, String columnName) throws SQLException;
/**
* 從結(jié)果集中根據(jù)列索引獲取數(shù)據(jù)并轉(zhuǎn)換為 java 對象
*
* @param rs 當前的結(jié)果集
* @param columnIndex 當前字段的位置
*/
T getResult(ResultSet rs, int columnIndex) throws SQLException;
/**
* 從存儲過程的結(jié)果集中根據(jù)列索引獲取數(shù)據(jù)并轉(zhuǎn)換為對應的Java類型
*
* @param cs 當前的CallableStatement執(zhí)行后的CallableStatement
* @param columnIndex 當前輸出參數(shù)的位置
*/
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
對于基本數(shù)據(jù)類型(如int、long、float等),MyBatis提供了內(nèi)置的 TypeHandler 實現(xiàn),這些實現(xiàn)能夠直接將 Java 基本數(shù)據(jù)類型轉(zhuǎn)換為對應的 JDBC 基本數(shù)據(jù)類型,反之亦然。在 MyBatis 的 TypeHandlerRegistry 類型中,可以看到內(nèi)置的類型處理器,這里整理常見的一些。
| TypeHandler | 描述 |
|---|---|
| BaseTypeHandler | 基礎類型處理器,用于處理Java基礎類型和JDBC類型之間的轉(zhuǎn)換,如Integer、String等。 |
| BooleanTypeHandler | 用于 java 類型 boolean,jdbc 類型 bit、boolean |
| ByteTypeHandler | 用于 java 類型 byte,jdbc 類型 TINYINT |
| ShortTypeHandler | 用于 java 類型 short,jdbc 類型 SMALLINT |
| IntegerTypeHandler | 用于 INTEGER 類型 |
| LongTypeHandler | 用于 long 類型 |
| FloatTypeHandler | 用于 FLOAT 類型 |
| DoubleTypeHandler | 用于 double 類型 |
| StringTypeHandler | 用于 java 類型 string,jdbc 類型 CHAR、VARCHAR |
| ArrayTypeHandler | 數(shù)組類型處理器,用于處理Java數(shù)組類型和JDBC數(shù)組類型之間的轉(zhuǎn)換。 |
| CollectionTypeHandler | 集合類型處理器,用于處理Java集合類型和JDBC集合類型之間的轉(zhuǎn)換。 |
以上只是 MyBatis 內(nèi)置 TypeHandler 的一部分示例,實際上 MyBatis 提供了更多的內(nèi)置 TypeHandler 以支持各種不同類型的數(shù)據(jù)轉(zhuǎn)換需求。在使用 MyBatis 時,可以根據(jù)具體的數(shù)據(jù)庫類型和 Java 類型選擇合適的內(nèi)置 TypeHandler,或者根據(jù)需要自定義 TypeHandler 來處理特殊的數(shù)據(jù)類型轉(zhuǎn)換場景。
2.2 BaseTypeHandler 抽象類
實際開發(fā)中,我們可以繼承 org.apache.ibatis.type.BaseTypeHandler 類型來實現(xiàn)自定義類型處理器。這個類型是抽象類型,實現(xiàn)了 TypeHandler 的方法進行通用流程的封裝,做了異常處理,并定義了幾個類似的抽象方法,使得創(chuàng)建自定義類型處理器時只需要覆蓋必要的方法。通常,如果不需要處理所有的JDBC類型,可以選擇繼承 BaseTypeHandler,可以極大地降低開發(fā)難度。BaseTypeHandler 提供了對 null 值的處理以及部分 TypeHandler 接口方法的默認實現(xiàn)。當繼承 BaseTypeHandler 時,通常需要實現(xiàn)或覆蓋以下方法:

// 設置非空的參數(shù)值,實現(xiàn)類需要覆蓋這個方法來設置非空參數(shù)。 void setNonNullParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException; // 根據(jù)列名獲取可能為null的結(jié)果,實現(xiàn)類需要覆蓋這個方法來獲取可能為空的結(jié)果。 T getNullableResult(ResultSet var1, String var2) throws SQLException; // 根據(jù)列索引獲取可能為null的結(jié)果,實現(xiàn)類需要覆蓋這個方法來獲取可能為空的結(jié)果。 T getNullableResult(ResultSet var1, int var2) throws SQLException; // 從存儲過程的結(jié)果集中根據(jù)列索引獲取可能為null的結(jié)果,實現(xiàn)類需要覆蓋這個方法來獲取可能為空的結(jié)果。 T getNullableResult(CallableStatement var1, int var2) throws SQLException;
這些方法專注于處理非空值的轉(zhuǎn)換以及處理從數(shù)據(jù)庫中檢索的可能為null的值,總的來說,TypeHandler 接口提供了完整的 JDBC 類型和 Java 類型轉(zhuǎn)換的契約,而 BaseTypeHandler 則是一個便利的基類,提供了一些基本的和通用的實現(xiàn),以減少自定義類型處理器時的代碼量。在創(chuàng)建自定義類型處理器時,可以根據(jù)具體需求選擇直接實現(xiàn) TypeHandler 接口還是繼承 BaseTypeHandler 類。
三、自定義類型處理器
盡管 MyBatis 提供了一系列內(nèi)置的 TypeHandler,用于處理常見的 Java 類型與數(shù)據(jù)庫類型之間的轉(zhuǎn)換。但在某些特殊情況下,可能需要自定義 TypeHandler 來實現(xiàn)任意復雜的類型轉(zhuǎn)換邏輯??梢酝ㄟ^實現(xiàn) TypeHandler 接口或繼承 BaseTypeHandler 類來創(chuàng)建自定義的TypeHandler實現(xiàn),以滿足特定業(yè)務需求。
3.1 創(chuàng)建自定義 TypeHandler
我們可以創(chuàng)建一個來自動轉(zhuǎn)義字符串內(nèi)容,現(xiàn)在我們創(chuàng)建一個 EscapedStringTypeHandler 來處理類型的轉(zhuǎn)義、反轉(zhuǎn)義,需要實現(xiàn) org.apache.ibatis.type.TypeHandler 接口或者繼承一個很便利的類 org.apache.ibatis.type.BaseTypeHandler。
import cn.hutool.http.HtmlUtil;
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 static org.apache.ibatis.type.JdbcType.*;
@MappedTypes(String.class)// 指定該Handler對應的Java類型
@MappedJdbcTypes(value = {CLOB,CLOB,VARCHAR,LONGVARCHAR,NVARCHAR,NCHAR,NCLOB}, includeNullJdbcType = true) // 指定對應的JDBC類型
public class EscapedStringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) throws SQLException {
// 對原數(shù)據(jù)不做處理
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
String data = resultSet.getString(columnName);
return StrUtil.isNotBlank(data) ? HtmlUtil.unescape(data) : null;
}
@Override
public String getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
String data = resultSet.getString(columnIndex);
return StrUtil.isNotBlank(data) ? HtmlUtil.unescape(data) : null;
}
@Override
public String getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
String data = callableStatement.getString(columnIndex);
return StrUtil.isNotBlank(data) ? HtmlUtil.unescape(data) : null;
}
}
??使用上述的類型處理器將會覆蓋已經(jīng)存在的處理 Java 的 String 類型屬性和 VARCHAR 參數(shù)及結(jié)果的類型處理器。 要注意 MyBatis 不會通過窺探數(shù)據(jù)庫元信息來決定使用哪種類型,所以你必須在參數(shù)和結(jié)果映射中指明那是 VARCHAR 類型的字段, 以使其能夠綁定到正確的類型處理器上。這是因為 MyBatis 直到語句被執(zhí)行時才清楚數(shù)據(jù)類型。
3.2 注冊自定義 TypeHandler
此外,MyBatis 還提供了豐富的 API 和擴展點來支持開發(fā)者自定義 TypeHandler 的注冊和使用方式。我們可以通過配置文件、注解或編程方式將自定義的 TypeHandler 注冊到MyBatis 中,如果是在 Spring Boot 環(huán)境中使用 MyBatis,可以在 application.yml 文件中,配置屬性來指定 TypeHandler 所在的包路徑,MyBatis 會自動掃描并注冊該包下的所有TypeHandler。以下是配置示例:
mybatis: type-handlers-package: com.dllwh.handler # 指定自定義TypeHandler的包位置
3.3 使用自定義 TypeHandler
接下來,我們在 Mapper 的 XML 映射文件中,通過 result 或 parameterType 屬性引用它們來處理特定的數(shù)據(jù)類型轉(zhuǎn)換需求。以下是配置示例:
<!-- Mapper XML中使用 -->
<resultMap id="personMap" type="person">
<id property="id" column="id" />
<!-- 指定typeHandler屬性為全類名-->
<result property="name" column="name" typeHandler="org.dllwh.handler.EscapedStringTypeHandler"/>/>
</resultMap>
<!-- Mapper XML中使用 -->
<select id="selectByExample" resultType="CustomJavaType">
SELECT * FROM table WHERE user_name = #{value, typeHandler=org.dllwh.handler.EscapedStringTypeHandler}
</select>
四、小結(jié)
TypeHandler 在 MyBatis 中扮演著非常重要的角色,它負責處理數(shù)據(jù)庫數(shù)據(jù)結(jié)構和bean對象數(shù)據(jù)類型之間的轉(zhuǎn)換。通過創(chuàng)建自定義的 TypeHandler,我們能夠靈活地處理 MyBatis 中復雜數(shù)據(jù)類型的轉(zhuǎn)換問題,提高開發(fā)效率和代碼可維護性。無論是 JSON、XML 還是其他復雜類型,自定義 TypeHandler 都能提供統(tǒng)一且方便的方式來實現(xiàn)這一目標。在實際項目中,合理使用 TypeHandler 能夠使數(shù)據(jù)映射更加清晰與高效,尤其是 Spring Boot 項目中,更是簡化了配置和注冊過程,使得開發(fā)者能夠更專注于業(yè)務邏輯的實現(xiàn)。
到此這篇關于一文搞懂MyBatis中TypeHandler機制的文章就介紹到這了,更多相關MyBatis TypeHandler內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Mybatis實現(xiàn)自定義的typehandler三步曲
- MyBatis自定義typeHandler的完整實例
- MyBatis-Plus如何通過注解使用TypeHandler
- Mybatis實現(xiàn)自定義類型轉(zhuǎn)換器TypeHandler的方法
- Mybatis中自定義TypeHandler處理枚舉詳解
- Mybatis自定義TypeHandler解決特殊類型轉(zhuǎn)換問題詳解
- Mybatis實戰(zhàn)之TypeHandler高級進階
- Mybatis之類型處理器TypeHandler的作用與自定義方式
- MyBatis使用自定義TypeHandler轉(zhuǎn)換類型的實現(xiàn)方法
- MyBatis-Plus?中?typeHandler?的使用實例詳解
- MyBatis中TypeHandler的使用教程詳解
相關文章
Java反射獲取所有Controller和RestController類的方法
這篇文章給大家分享了Java反射獲取所有Controller和RestController類的方法,文中有詳細的代碼示例講解,具有一定的參考價值,需要的朋友可以參考下2023-08-08
Android開發(fā)Kotlin實現(xiàn)圓弧計步器示例詳解
這篇文章主要為大家介紹了Android開發(fā)Kotlin繪制圓弧計步器示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06
java鏈表數(shù)據(jù)結(jié)構LinkedList插入刪除元素時間復雜度面試精講
這篇文章主要為大家介紹了java LinkedList插入和刪除元素的時間復雜度面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10
SpringBoot整合Swagger頁面禁止訪問swagger-ui.html方式
本文介紹了如何在SpringBoot項目中通過配置SpringSecurity和創(chuàng)建攔截器來禁止訪問SwaggerUI頁面,此外,還提供了禁用SwaggerUI和Swagger資源的配置方法,以確保這些端點和頁面對外部用戶不可見或無法訪問2025-02-02
Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別
很多朋友對java中的notyfy()和notifyAll()的本質(zhì)區(qū)別不了解,今天小編抽空給大家整理一篇教程關于Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別,需要的朋友參考下吧2017-02-02

