欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis類型轉(zhuǎn)換模塊的實現(xiàn)

 更新時間:2023年09月22日 09:58:01   作者:叫我二蛋  
MyBatis是一個持久層框架ORM框架,實現(xiàn)數(shù)據(jù)庫中數(shù)據(jù)和Java對象中的屬性的雙向映射,那么不可避免的就會碰到類型轉(zhuǎn)換的問題,本文主要介紹了MyBatis類型轉(zhuǎn)換模塊的實現(xiàn),感興趣的可以了解一下

前言

MyBatis是一個持久層框架ORM框架,實現(xiàn)數(shù)據(jù)庫中數(shù)據(jù)和Java對象中的屬性的雙向映射,那么不可避免的就會碰到類型轉(zhuǎn)換的問題,在PreparedStatement為SQL語句綁定參數(shù)時,需要從Java類型轉(zhuǎn)換為JDBC類型,而從結(jié)果集中獲取數(shù)據(jù)時,則需要從JDBC類型轉(zhuǎn)換為Java類型,所以本文來看下在MyBatis中是如何實現(xiàn)類型的轉(zhuǎn)換的。

TypeHandler

MyBatis中的所有的類型轉(zhuǎn)換器都繼承了TypeHandler接口,在TypeHandler中定義了類型轉(zhuǎn)換器的最基本的功能。

/**
 * @author Clinton Begin
 */
public interface TypeHandler<T> {
  /**
   * 負(fù)責(zé)將Java類型轉(zhuǎn)換為JDBC的類型
   *    本質(zhì)上執(zhí)行的就是JDBC操作中的 如下操作
   *        String sql = "SELECT id,user_name,real_name,password,age,d_id from t_user where id = ? and user_name = ?";
   *        ps = conn.prepareStatement(sql);
   *        ps.setInt(1,2);
   *        ps.setString(2,"張三");
   * @param ps
   * @param i 對應(yīng)占位符的 位置
   * @param parameter 占位符對應(yīng)的值
   * @param jdbcType 對應(yīng)的 jdbcType 類型
   * @throws SQLException
   */
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  /**
   * 從ResultSet中獲取數(shù)據(jù)時會調(diào)用此方法,會將數(shù)據(jù)由JdbcType轉(zhuǎn)換為Java類型
   * @param columnName Colunm name, when configuration <code>useColumnLabel</code> is <code>false</code>
   */
  T getResult(ResultSet rs, String columnName) throws SQLException;
  T getResult(ResultSet rs, int columnIndex) throws SQLException;
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}

BaseTypeHandler

為了方便用戶自定義TypeHandler的實現(xiàn),在MyBatis中提供了BaseTypeHandler這個抽象類,它實現(xiàn)了TypeHandler接口,并繼承了TypeReference類,

image.png

在BaseTypeHandler中的實現(xiàn)方法中實現(xiàn)了對null的處理,非空的處理是交給各個子類去實現(xiàn)的。這個在代碼中很清楚的體現(xiàn)了出來

TypeHandler實現(xiàn)類

TypeHandler的實現(xiàn)類比較多,而且實現(xiàn)也都比較簡單。

image.png

以Integer為例

/**
 * @author Clinton Begin
 */
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setInt(i, parameter); // 實現(xiàn)參數(shù)的綁定
  }
  @Override
  public Integer getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    int result = rs.getInt(columnName); // 獲取指定列的值
    return result == 0 && rs.wasNull() ? null : result;
  }
  @Override
  public Integer getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    int result = rs.getInt(columnIndex); // 獲取指定列的值
    return result == 0 && rs.wasNull() ? null : result;
  }
  @Override
  public Integer getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    int result = cs.getInt(columnIndex); // 獲取指定列的值
    return result == 0 && cs.wasNull() ? null : result;
  }
}

TypeHandlerRegistry

在MyBatis中給我們提供的具體的類型轉(zhuǎn)換器實在是太多了,那么在實際的使用時我們是如何知道使用哪個轉(zhuǎn)換器類處理的呢?實際上再MyBatis中是將所有的TypeHandler都保存注冊在了TypeHandlerRegistry中的。首先注意聲明的相關(guān)屬性

  // 記錄JdbcType和TypeHandle的對應(yīng)關(guān)系
  private final Map<JdbcType, TypeHandler<?>>  jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
  // 記錄Java類型向指定的JdbcType轉(zhuǎn)換時需要使用到的TypeHandle
  private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
  private final TypeHandler<Object> unknownTypeHandler;
  // 記錄全部的TypeHandle類型及對應(yīng)的TypeHandle對象
  private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
  // 空TypeHandle的標(biāo)識
  private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();

在器構(gòu)造方法中完成了系統(tǒng)提供的TypeHandler的注冊

image.png

有注冊的方法,當(dāng)然也有從注冊器中獲取TypeHandler的方法,getTypeHandler方法,這個方法也有多個重載的方法,這里重載的方法最終都會執(zhí)行的方法是

  /**
   * 根據(jù)對應(yīng)的Java類型和Jdbc類型來查找對應(yīng)的TypeHandle
   */
  private <T> TypeHandler<T> getTypeHandler(Type type, JdbcType jdbcType) {
    if (ParamMap.class.equals(type)) {
      return null;
    }
    // 根據(jù)Java類型獲取對應(yīng)的 Jdbc類型和TypeHandle的集合容器
    Map<JdbcType, TypeHandler<?>> jdbcHandlerMap = getJdbcHandlerMap(type);
    TypeHandler<?> handler = null;
    if (jdbcHandlerMap != null) {
      // 根據(jù)Jdbc類型獲取對應(yīng)的 處理器
      handler = jdbcHandlerMap.get(jdbcType);
      if (handler == null) {
        // 獲取null對應(yīng)的處理器
        handler = jdbcHandlerMap.get(null);
      }
      if (handler == null) {
        // #591
        handler = pickSoleHandler(jdbcHandlerMap);
      }
    }
    // type drives generics here
    return (TypeHandler<T>) handler;
  }

除了使用系統(tǒng)提供的TypeHandler以外,還可以創(chuàng)建自己的TypeHandler了,具體使用見MyBatis 核心配置。

TypeAliasRegistry

在MyBatis的應(yīng)用的時候會經(jīng)常用到別名,這能大大簡化我們的代碼,其實在MyBatis中是通過TypeAliasRegistry類管理的。

image.png

注冊的方法邏輯也比較簡單

  public void registerAlias(String alias, Class<?> value) {
    if (alias == null) {
      throw new TypeException("The parameter alias cannot be null");
    }
    // issue #748 別名統(tǒng)一轉(zhuǎn)換為小寫
    String key = alias.toLowerCase(Locale.ENGLISH);
    // 檢測別名是否存在
    if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
      throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
    }
    // 將 別名 和 類型 添加到 Map 集合中
    typeAliases.put(key, value);
  }

TypeHandler的應(yīng)用

SqlSessionFactory

在構(gòu)建SqlSessionFactory時,在Configuration對象實例化的時候在成員變量中完成了TypeHandlerRegistry和TypeAliasRegistry的實例化

image.png

在TypeHandlerRegistry的構(gòu)造方法中完成了常用類型的TypeHandler的注冊

image.png

在TypeAliasRegistry中完成了常用Java類型別名的注冊

image.png

在Configuration的構(gòu)造方法中會為各種常用的類型向TypeAliasRegistry中注冊類型別名數(shù)據(jù)

image.png

以上步驟完成了TypeHandlerRegistry和TypeAliasRegistry的初始化操作

然后在解析全局配置文件時會通過解析<typeAliases>標(biāo)簽和<typeHandlers>標(biāo)簽,可以注冊我們添加的別名和TypeHandler。

image.png

在全局配置文件中指定了對應(yīng)的別名,那么在映射文件中就可以簡寫類型了,這樣在解析映射文件時,我們同樣也是需要做別名的處理的。

image.png

這個parameterType就可以是我們定義的別名,然后在 resolveClass中就會做對應(yīng)的處理

  protected <T> Class<? extends T> resolveClass(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      return resolveAlias(alias); // 別名處理
    } catch (Exception e) {
      throw new BuilderException("Error resolving class. Cause: " + e, e);
    }
  }
  protected <T> Class<? extends T> resolveAlias(String alias) {
    return typeAliasRegistry.resolveAlias(alias); // 根據(jù)別名查找真實的類型
  }

執(zhí)行SQL語句

TypeHandler類型處理器使用比較多的地方應(yīng)該是在給SQL語句中參數(shù)綁定值和查詢結(jié)果和對象中屬性映射的地方用到的比較多,

DefaultParameterHandler中看看參數(shù)是如何處理的

  /**
  * 為 SQL 語句中的 ? 占位符 綁定實參
  */
  @Override
  public void setParameters(PreparedStatement ps) {
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
      // 取出SQL中的參數(shù)映射列表
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); // 獲取對應(yīng)的占位符
    if (parameterMappings != null) {
      for (int i = 0; i < parameterMappings.size(); i++) {
        ParameterMapping parameterMapping = parameterMappings.get(i);
        if (parameterMapping.getMode() != ParameterMode.OUT) { // 過濾掉存儲過程中的 輸出參數(shù)
          Object value;
          String propertyName = parameterMapping.getProperty();
          if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
            value = boundSql.getAdditionalParameter(propertyName);
          } else if (parameterObject == null) {
            value = null;
          } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { // 
            value = parameterObject;
          } else {
            MetaObject metaObject = configuration.newMetaObject(parameterObject);
            value = metaObject.getValue(propertyName);
          }
          // 獲取 參數(shù)類型 對應(yīng)的 類型處理器
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
          JdbcType jdbcType = parameterMapping.getJdbcType();
          if (value == null && jdbcType == null) {
            jdbcType = configuration.getJdbcTypeForNull();
          }
          try {
            // 通過TypeHandler 處理參數(shù)
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
          } catch (TypeException | SQLException e) {
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
          }
        }
      }
    }
  }

然后進(jìn)入到DefaultResultSetHandler中的getRowValue方法中

image.png

然后再進(jìn)入applyAutomaticMappings方法中查看

image.png

可以看到,根據(jù)對應(yīng)的TypeHandler返回對應(yīng)類型的值。

到此這篇關(guān)于MyBatis類型轉(zhuǎn)換模塊的實現(xiàn)的文章就介紹到這了,更多相關(guān)MyBatis類型轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springboot整合sentinel的方法教程

    springboot整合sentinel的方法教程

    這篇文章主要介紹了springboot整合sentinel的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • IDEA如何設(shè)置忽略git提交的文件

    IDEA如何設(shè)置忽略git提交的文件

    這篇文章主要介紹了IDEA如何設(shè)置忽略git提交的文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • java中URLEncoder.encode與URLDecoder.decode處理url特殊參數(shù)的方法

    java中URLEncoder.encode與URLDecoder.decode處理url特殊參數(shù)的方法

    這篇文章主要給大家介紹了關(guān)于java中URLEncoder.encode與URLDecoder.decode處理url特殊參數(shù)的方法,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-03-03
  • SpringBoot異步使用@Async的原理以及線程池配置詳解

    SpringBoot異步使用@Async的原理以及線程池配置詳解

    在項目中當(dāng)訪問其他人的接口較慢時,不想程序一直卡在耗時任務(wù)上,想程序能夠并行執(zhí)行,我們可以使用多線程來并行的處理任務(wù),也可以使用spring提供的異步處理方式@Async,這篇文章主要給大家介紹了關(guān)于SpringBoot異步使用@Async的原理以及線程池配置的相關(guān)資料
    2021-09-09
  • 關(guān)于Springboot中JSCH的使用及說明

    關(guān)于Springboot中JSCH的使用及說明

    這篇文章主要介紹了關(guān)于Springboot中JSCH的使用及說明,具有很好的參考價值,希望對大家有所幫助。
    2022-09-09
  • java實現(xiàn)PPT轉(zhuǎn)化為PDF

    java實現(xiàn)PPT轉(zhuǎn)化為PDF

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)PPT轉(zhuǎn)化為PDF的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Java 文件上傳的實例詳解

    Java 文件上傳的實例詳解

    這篇文章主要介紹了Java 文件上傳的實例詳解的相關(guān)資料,希望通過本文大家能掌握這部分內(nèi)容,使用幾種文件上傳的方法,需要的朋友可以參考下
    2017-09-09
  • java基于GUI實現(xiàn)簡單畫筆小畫板

    java基于GUI實現(xiàn)簡單畫筆小畫板

    這篇文章主要為大家詳細(xì)介紹了java基于GUI實現(xiàn)簡單畫筆小畫板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Spring學(xué)習(xí)筆記3之消息隊列(rabbitmq)發(fā)送郵件功能

    Spring學(xué)習(xí)筆記3之消息隊列(rabbitmq)發(fā)送郵件功能

    這篇文章主要介紹了Spring學(xué)習(xí)筆記3之消息隊列(rabbitmq)發(fā)送郵件功能的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-07-07
  • Java后端SSM框架圖片上傳功能實現(xiàn)方法解析

    Java后端SSM框架圖片上傳功能實現(xiàn)方法解析

    這篇文章主要介紹了Java后端SSM框架圖片上傳功能實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-06-06

最新評論