MyBatis 3 XML配置-類(lèi)型處理器

2022-04-07 15:04 更新

MyBatis 在設(shè)置預(yù)處理語(yǔ)句(?PreparedStatement?)中的參數(shù)或從結(jié)果集中取出一個(gè)值時(shí), 都會(huì)用類(lèi)型處理器將獲取到的值以合適的方式轉(zhuǎn)換成 Java 類(lèi)型。下表描述了一些默認(rèn)的類(lèi)型處理器。

從 3.4.5 開(kāi)始,MyBatis 默認(rèn)支持 JSR-310(日期和時(shí)間 API) 。

類(lèi)型處理器 Java 類(lèi)型 JDBC 類(lèi)型
BooleanTypeHandler java.lang.Booleanboolean 數(shù)據(jù)庫(kù)兼容的 BOOLEAN
ByteTypeHandler java.lang.Bytebyte 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 BYTE
ShortTypeHandler java.lang.Shortshort 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 SMALLINT
IntegerTypeHandler java.lang.Integerint 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 INTEGER
LongTypeHandler java.lang.Longlong 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 BIGINT
FloatTypeHandler java.lang.Floatfloat 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 FLOAT
DoubleTypeHandler java.lang.Doubledouble 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 DOUBLE
BigDecimalTypeHandler java.math.BigDecimal 數(shù)據(jù)庫(kù)兼容的 NUMERIC 或 DECIMAL
StringTypeHandler java.lang.String CHARVARCHAR
ClobReaderTypeHandler java.io.Reader -
ClobTypeHandler java.lang.String CLOBLONGVARCHAR
NStringTypeHandler java.lang.String NVARCHARNCHAR
NClobTypeHandler java.lang.String NCLOB
BlobInputStreamTypeHandler java.io.InputStream -
ByteArrayTypeHandler byte[] 數(shù)據(jù)庫(kù)兼容的字節(jié)流類(lèi)型
BlobTypeHandler byte[] BLOBLONGVARBINARY
DateTypeHandler java.util.Date TIMESTAMP
DateOnlyTypeHandler java.util.Date DATE
TimeOnlyTypeHandler java.util.Date TIME
SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP
SqlDateTypeHandler java.sql.Date DATE
SqlTimeTypeHandler java.sql.Time TIME
ObjectTypeHandler Any OTHER 或未指定類(lèi)型
EnumTypeHandler Enumeration Type VARCHAR 或任何兼容的字符串類(lèi)型,用來(lái)存儲(chǔ)枚舉的名稱(chēng)(而不是索引序數(shù)值)
EnumOrdinalTypeHandler Enumeration Type 任何兼容的 NUMERIC 或 DOUBLE 類(lèi)型,用來(lái)存儲(chǔ)枚舉的序數(shù)值(而不是名稱(chēng))。
SqlxmlTypeHandler java.lang.String SQLXML
InstantTypeHandler java.time.Instant TIMESTAMP
LocalDateTimeTypeHandler java.time.LocalDateTime TIMESTAMP
LocalDateTypeHandler java.time.LocalDate DATE
LocalTimeTypeHandler java.time.LocalTime TIME
OffsetDateTimeTypeHandler java.time.OffsetDateTime TIMESTAMP
OffsetTimeTypeHandler java.time.OffsetTime TIME
ZonedDateTimeTypeHandler java.time.ZonedDateTime TIMESTAMP
YearTypeHandler java.time.Year INTEGER
MonthTypeHandler java.time.Month INTEGER
YearMonthTypeHandler java.time.YearMonth VARCHAR 或 LONGVARCHAR
JapaneseDateTypeHandler java.time.chrono.JapaneseDate DATE

你可以重寫(xiě)已有的類(lèi)型處理器或創(chuàng)建你自己的類(lèi)型處理器來(lái)處理不支持的或非標(biāo)準(zhǔn)的類(lèi)型。 具體做法為:實(shí)現(xiàn) ?org.apache.ibatis.type.TypeHandler? 接口, 或繼承一個(gè)很便利的類(lèi) ?org.apache.ibatis.type.BaseTypeHandler?, 并且可以(可選地)將它映射到一個(gè) ?JDBC類(lèi)型。比如:

// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
    ps.setString(i, parameter);
  }

  @Override
  public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return rs.getString(columnName);
  }

  @Override
  public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return rs.getString(columnIndex);
  }

  @Override
  public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return cs.getString(columnIndex);
  }
}
<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

使用上述的類(lèi)型處理器將會(huì)覆蓋已有的處理 Java ?String類(lèi)型的屬性以及 ?VARCHAR ?類(lèi)型的參數(shù)和結(jié)果的類(lèi)型處理器。 要注意 MyBatis 不會(huì)通過(guò)檢測(cè)數(shù)據(jù)庫(kù)元信息來(lái)決定使用哪種類(lèi)型,所以你必須在參數(shù)和結(jié)果映射中指明字段是 ?VARCHAR類(lèi)型, 以使其能夠綁定到正確的類(lèi)型處理器上。這是因?yàn)?nbsp;MyBatis 直到語(yǔ)句被執(zhí)行時(shí)才清楚數(shù)據(jù)類(lèi)型。

通過(guò)類(lèi)型處理器的泛型,MyBatis 可以得知該類(lèi)型處理器處理的 Java 類(lèi)型,不過(guò)這種行為可以通過(guò)兩種方法改變:

  • 在類(lèi)型處理器的配置元素(?typeHandler元素)上增加一個(gè) ?javaType? 屬性(比如:?javaType="String"?);
  • 在類(lèi)型處理器的類(lèi)上增加一個(gè) ?@MappedTypes? 注解指定與其關(guān)聯(lián)的 Java 類(lèi)型列表。 如果在 ?javaType屬性中也同時(shí)指定,則注解上的配置將被忽略。

可以通過(guò)兩種方式來(lái)指定關(guān)聯(lián)的 ?JDBC類(lèi)型:

  • 在類(lèi)型處理器的配置元素上增加一個(gè) ?jdbcType屬性(比如:?jdbcType="VARCHAR"?);
  • 在類(lèi)型處理器的類(lèi)上增加一個(gè) ?@MappedJdbcTypes? 注解指定與其關(guān)聯(lián)的 ?JDBC類(lèi)型列表。 如果在 ?jdbcType屬性中也同時(shí)指定,則注解上的配置將被忽略。

當(dāng)在 ?ResultMap中決定使用哪種類(lèi)型處理器時(shí),此時(shí) Java 類(lèi)型是已知的(從結(jié)果類(lèi)型中獲得),但是 ?JDBC類(lèi)型是未知的。 因此 Mybatis 使用?javaType=[Java 類(lèi)型], jdbcType=null? 的組合來(lái)選擇一個(gè)類(lèi)型處理器。 這意味著使用 ?@MappedJdbcTypes? 注解可以限制類(lèi)型處理器的作用范圍,并且可以確保,除非顯式地設(shè)置,否則類(lèi)型處理器在 ?ResultMap中將不會(huì)生效。 如果希望能在 ?ResultMap中隱式地使用類(lèi)型處理器,那么設(shè)置 ?@MappedJdbcTypes? 注解的 ?includeNullJdbcType=true? 即可。 然而從 Mybatis 3.4.0 開(kāi)始,如果某個(gè) Java 類(lèi)型只有一個(gè)注冊(cè)的類(lèi)型處理器,即使沒(méi)有設(shè)置 ?includeNullJdbcType=true?,那么這個(gè)類(lèi)型處理器也會(huì)是 ?ResultMap使用 Java 類(lèi)型時(shí)的默認(rèn)處理器。

最后,可以讓 MyBatis 幫你查找類(lèi)型處理器:

<!-- mybatis-config.xml -->
<typeHandlers>
  <package name="org.mybatis.example"/>
</typeHandlers>

注意在使用自動(dòng)發(fā)現(xiàn)功能的時(shí)候,只能通過(guò)注解方式來(lái)指定JDBC的類(lèi)型。

你可以創(chuàng)建能夠處理多個(gè)類(lèi)的泛型類(lèi)型處理器。為了使用泛型類(lèi)型處理器, 需要增加一個(gè)接受該類(lèi)的 class 作為參數(shù)的構(gòu)造器,這樣 MyBatis 會(huì)在構(gòu)造一個(gè)類(lèi)型處理器實(shí)例的時(shí)候傳入一個(gè)具體的類(lèi)。

//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {

  private Class<E> type;

  public GenericTypeHandler(Class<E> type) {
    if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
    this.type = type;
  }
  ...

?EnumTypeHandler和 ?EnumOrdinalTypeHandler都是泛型類(lèi)型處理器,我們將會(huì)在接下來(lái)的部分詳細(xì)探討。

處理枚舉類(lèi)型

若想映射枚舉類(lèi)型 ?Enum?,則需要從 ?EnumTypeHandler或者 ?EnumOrdinalTypeHandler中選擇一個(gè)來(lái)使用。

比如說(shuō)我們想存儲(chǔ)取近似值時(shí)用到的舍入模式。默認(rèn)情況下,MyBatis 會(huì)利用 ?EnumTypeHandler來(lái)把 ?Enum值轉(zhuǎn)換成對(duì)應(yīng)的名字。

注意 ?EnumTypeHandler在某種意義上來(lái)說(shuō)是比較特別的,其它的處理器只針對(duì)某個(gè)特定的類(lèi),而它不同,它會(huì)處理任意繼承了Enum的類(lèi)。

不過(guò),我們可能不想存儲(chǔ)名字,相反我們的DBA會(huì)堅(jiān)持使用整形值代碼。那也一樣簡(jiǎn)單:在配置文件中把EnumOrdinalTypeHandler加到typeHandlers中即可, 這樣每個(gè) ?RoundingMode將通過(guò)他們的序數(shù)值來(lái)映射成對(duì)應(yīng)的整形數(shù)值。

<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>

但要是你想在一個(gè)地方將Enum映射成字符串,在另外一個(gè)地方映射成整形值呢?

自動(dòng)映射器(?auto-mapper?)會(huì)自動(dòng)地選用 ?EnumOrdinalTypeHandler來(lái)處理枚舉類(lèi)型, 所以如果我們想用普通的 ?EnumTypeHandler?,就必須要顯式地為那些 SQL 語(yǔ)句設(shè)置要使用的類(lèi)型處理器。

(下一節(jié)才開(kāi)始介紹映射器文件,如果你是首次閱讀該文檔,你可能需要先跳過(guò)這里,過(guò)會(huì)再來(lái)看。)

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
	<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<result column="funkyNumber" property="funkyNumber"/>
		<result column="roundingMode" property="roundingMode"/>
	</resultMap>

	<select id="getUser" resultMap="usermap">
		select * from users
	</select>
	<insert id="insert">
	    insert into users (id, name, funkyNumber, roundingMode) values (
	    	#{id}, #{name}, #{funkyNumber}, #{roundingMode}
	    )
	</insert>

	<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		<result column="funkyNumber" property="funkyNumber"/>
		<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
	</resultMap>
	<select id="getUser2" resultMap="usermap2">
		select * from users2
	</select>
	<insert id="insert2">
	    insert into users2 (id, name, funkyNumber, roundingMode) values (
	    	#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
	    )
	</insert>

</mapper>

注意,這里的 ?select語(yǔ)句必須指定 ?resultMap而不是 ?resultType?。


以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)