Ibatis的類型處理器TypeHandler解析


  Ibatis允許用戶像在hibernate中一樣定義自己的類型,但是,用戶自定義類型需要與數據庫中的字段類型進行對應。它的處理方法是允許我們擴展TypeHandler。Ibatis框架在處理該數據類型時就會自動調用TypeHandler進行類型轉換,非常方便,ibatis中所有的類型都有它自己的TypeHandler,只是一些常用的數據類類型它已經給我們實現了而已。

  在配置文件中,我們有兩個地方可以配置這種處理器。

  第一個地方是sqlMap文件中標簽ResultMap或者ParameterMap中的TypeHandler屬性,這里配置的handler是局部屬性,只會在該ResultMap中才會進行轉換。

<resultMap id="UserOrder" class="UserOrderDO" groupBy="id">
         ......
        <result property="tripType" column="trip_Type"
         typeHandler="com.taobao.et.biz.dal.common.EnumTypeHandlerCallBack"/>
          ......
</resultMap>

   第二個地方是sqlMapConfig文件中的標簽typeHandlers中配置typeHandle子標簽,這里配置的標簽是全局屬性,任何只要匹配該子標簽的地方都會自動使用該Handler.

<typeHandlers>
<typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
</typeHandlers>

  例如這里的全局配置,如果此時某個數據庫字段的jdbcType是CLOB類型,並且映射的JavaType類型是字符串類型,那么就會自動調用這里的callback來實行類型轉換。

  那么Ibatis是如何確定使用哪一個TypeHandler的呢?!

      它會在自己的局部區域尋找是否在配置文件中配置了Handler,找到了就使用這個handler,如果沒有找到,就會查找是否有全局handler,也就是第二種方式配置的handler,這里要注意,可能我們也沒有在全局配置文件中配置handler,此時,Ibatis就會根據實際類型配置默認的handler。

      我們來看一些關鍵代碼,按照查找步驟,這里我去掉了異常,只看關鍵的部分。

      第一步:從局部Reultmap中取出配置屬性。

     String propertyName = childAttributes.getProperty("property");
        String nullValue = childAttributes.getProperty("nullValue");
        String jdbcType = childAttributes.getProperty("jdbcType");
        String javaType = childAttributes.getProperty("javaType");
        String columnName = childAttributes.getProperty("column");
        String columnIndex = childAttributes.getProperty("columnIndex");
        String statementName = childAttributes.getProperty("select");
        String resultMapName = childAttributes.getProperty("resultMap");
        String callback = childAttributes.getProperty("typeHandler");
        callback = vars.typeHandlerFactory.resolveAlias(callback);
        javaType = vars.typeHandlerFactory.resolveAlias(javaType);
        TypeHandler handler = null;
        if (callback != null) { // 注意這里,如果配置了就使用這個配置的handler
            Object impl = Resources.classForName(callback).newInstance();
            if (impl instanceof TypeHandlerCallback) {
              handler = new CustomTypeHandler((TypeHandlerCallback) impl);
            } else if (impl instanceof TypeHandler) {
              handler = (TypeHandler) impl;
            } else {
              throw new NestedRuntimeException ("The class '' is not a valid implementation of TypeHandler or TypeHandlerCallback");
            }
        } else {//如果沒有配置,就到這里來找
                  handler = resolveTypeHandler(vars.client.getDelegate().getTypeHandlerFactory(), vars.currentResultMap.getResultClass(), propertyName, javaType, jdbcType, true);
        }

  第二步,如果局部配置中沒有找到,就到下面去找。

public TypeHandler resolveTypeHandler(TypeHandlerFactory typeHandlerFactory, Class clazz, String propertyName, String javaType, String jdbcType, boolean useSetterToResolve) {
    TypeHandler handler = null;
    if (clazz == null) {
      // Unknown
      handler = typeHandlerFactory.getUnkownTypeHandler();
    } else if (DomTypeMarker.class.isAssignableFrom(clazz)) {
      // DOM
      handler = typeHandlerFactory.getTypeHandler(String.class, jdbcType);
    } else if (java.util.Map.class.isAssignableFrom(clazz)) {
      // Map
      if (javaType == null) {
        handler = typeHandlerFactory.getUnkownTypeHandler(); //BUG 1012591 - typeHandlerFactory.getTypeHandler(java.lang.Object.class, jdbcType);
      } else {
        try {
          Class javaClass = Resources.classForName(javaType);
          handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
        } catch (Exception e) {
          throw new NestedRuntimeException("Error.  Could not set TypeHandler.  Cause: " + e, e);
        }
      }
    } else if (typeHandlerFactory.getTypeHandler(clazz, jdbcType) != null) {
      // Primitive
      handler = typeHandlerFactory.getTypeHandler(clazz, jdbcType);
    } else {
      // JavaBean
      if (javaType == null) {
        if (useSetterToResolve) {
          Class type = PROBE.getPropertyTypeForSetter(clazz, propertyName);
          handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
        } else {
          Class type = PROBE.getPropertyTypeForGetter(clazz, propertyName);
          handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
        }
      } else {
        try {
          Class javaClass = Resources.classForName(javaType);
          handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
        } catch (Exception e) {
          throw new NestedRuntimeException("Error.  Could not set TypeHandler.  Cause: " + e, e);
        }
      }
    }
    return handler;
  }
  1. 相信大家已經很明白了,其實要找一個Handler,主要就是需要javaType和jdbcType,而這兩個參數要么通過反射得到,要么通過配置文件中得到。因此,為了明確我們一般都在配置文件中進行申明。
  2. 最后來看一點 typeHandlerFactory.getTypeHandler(clazz, jdbcType)是怎么實現的。
public TypeHandler getTypeHandler(Class type, String jdbcType) {
    Map jdbcHandlerMap = (Map) typeHandlerMap.get(type);//首先根據JAVA類型
    TypeHandler handler = null;
    if (jdbcHandlerMap != null) {
      handler = (TypeHandler) jdbcHandlerMap.get(jdbcType);//每個JDBC類型
      if (handler == null) {
        handler = (TypeHandler) jdbcHandlerMap.get(null);
      }
    }
    return handler;
  }

  其實一個Handler=javaType+jdbcType 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM