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>
這種情況下就配置了一個只有null
的jdbcType。
實際上大多數人可能都是這麼配置的,因此都沒有遇到過這個異常。