1. 程式人生 > >Mybatis 示例之 TypeHandler

Mybatis 示例之 TypeHandler

關於TypeHandler的基礎內容可以參考官方中文文件:

TypeHandler寫起來很容易,但是有一個很重要的點需要注意。

你是否遇到過類似下面的錯誤:

Caused by: java.lang.RuntimeException: 呼叫方法異常:java.lang.IllegalStateException: Type handler was null on parameter mapping for property 'xxx'.  It was either not specified and/or could not be found for the javaType / jdbcType combination specified.

如果你遇到了這個問題,那麼這篇部落格正好適合你。如果你還沒遇到,也可以避免遇到這個問題。

先說錯誤的原因,MyBatis在查詢型別的TypeHandler的時候,呼叫下面的方法:

private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
  Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = TYPE_HANDLER_MAP.get(type);
  TypeHandler<?> handler = null
; if (jdbcHandlerMap != null) { handler = jdbcHandlerMap.get(jdbcType); if (handler == null) { handler = jdbcHandlerMap.get(null); } } if (handler == null && type != null && type instanceof Class && Enum.class.isAssignableFrom((Class<?>) type)) { handler = new
EnumTypeHandler((Class<?>) type); } // type drives generics here return (TypeHandler<T>) handler; }

一般情況下我們如果在Mapper.xml中使用的resultType,或者使用的resultMap但是resultMap的配置中沒有指定特殊型別欄位的jdbcType,就會出現上面的錯誤。

從上面原始碼很容易能看出來,當jdbcType是null的時候:

handler = jdbcHandlerMap.get(jdbcType);
if (handler == null) {
  handler = jdbcHandlerMap.get(null);
}

jdbcHandlerMap.get(jdbcType)jdbcHandlerMap.get(null)作用是一樣的,結果都是null,因此就會報出上面提到的錯誤。

這個錯誤如何解決呢?

如果僅從上面錯誤的原因配置一個jdbcType也解決不了使用resultType時的問題。

從原始碼handler = jdbcHandlerMap.get(null);這裡可以看到,預設情況下如果有jdbcType,但是handler=null,也會嘗試取出一個key為null的handler。

也就是說一般情況下,我們自己配置的TypeHandler都需要有一個key=null的鍵值。

如何設定一個null的key呢?如果你認為是列舉型別JdbcType.NULL那就錯了。

TypeHandler有兩種設定null的方式:

1. @MappedJdbcTypes註解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MappedJdbcTypes {
    public JdbcType[] value();
    boolean includeNullJdbcType() default false;
}

該註解包含一個屬性includeNullJdbcType,將該屬性設定為true即可。

2. xml配置

首先重點說明一下:如果使用了上面的註解配置,那麼在xml中的jdbcType配置不會起作用,會完全使用註解中的配置。

xml配置方法很簡單,那就是不要配置jdbcType屬性,例如:

<!-- mybatis-config.xml -->
<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>

這種情況下就配置了一個只有nulljdbcType

實際上大多數人可能都是這麼配置的,因此都沒有遇到過這個異常。