成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【Mybatis系列】從源碼角度理解Mybatis字段映射-AS&ResultMap

Zhuxy / 3023人閱讀

摘要:北京解決辦法在字段的時候使用,下面是改動后的映射文件。北京那么我們來看看它是如何生效的,主要的代碼在哪里。源碼層面的話,依舊在的中處理返回集合??偨Y(jié)大致上,完成映射主要是兩種方式。使用預(yù)先定義好映射關(guān)系,也是最后根據(jù)和反射,完成字段的賦值。

前言

考慮到在Select時使用AS和方案一其實沒什么差別,在介紹ResultMap之前,順便帶過一下。

方案二-Select .... AS

當(dāng)我們的數(shù)據(jù)庫列名和對象字段之間不是駝峰式命名的關(guān)系,我們可以在Select時使用AS,使得列名和對象名匹配上。
映射文件中是本次會執(zhí)行的sql,我們會查出id,city_id,city_name,city_en_name。 按照開啟的駝峰式命名開關(guān),我們會對應(yīng)到對象的id,cityId,cityName,cityEnName字段。

不過在這次,我們對PO做了小小的改動,把cityEnName改成了cityEnglishName。

public class CityPO {
    Integer id;
    Long cityId;
    String cityName;
    String cityEnglishName;   // 由cityEnName改成了cityEnglishName

由于找不到匹配的列,cityEnlishName肯定沒法被反射賦值,要為Null了。

CityPO{id=2, cityId=2, cityName="北京", cityEnglishName="null"} 

解決辦法: 在Select字段的時候使用AS,下面是改動后的映射文件。

改動后執(zhí)行得到的結(jié)果如下。

CityPO{id=2, cityId=2, cityName="北京", cityEnglishName="beijing"} 

那么我們來看看它是如何生效的,主要的代碼在哪里。在昨天我們第一個介紹的函數(shù)handleRowValues中傳入了參數(shù)rsw,它是對ResultSet的一個包裝,在這個包裝里,完成了具體使用哪個名字作為數(shù)據(jù)庫的列名。

final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);

在這個構(gòu)造函數(shù)當(dāng)中,我們會獲取數(shù)據(jù)庫的列名,AS為什么可以生效,具體就在下面這段代碼。

super();
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.resultSet = rs;
final ResultSetMetaData metaData = rs.getMetaData();
final int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
      // 在這里
      columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));
      jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));
      classNames.add(metaData.getColumnClassName(i));
}

在添加列名時,會從配置中獲取是否使用類標(biāo)簽,isUseColumnLabel,默認為true。根據(jù)Javadoc,這個ColumnLabel就是AS后的那個名字,如果沒有AS的話,就是獲取的原生的字段名。

    /**
     * Gets the designated column"s suggested title for use in printouts and
     * displays. The suggested title is usually specified by the SQL AS
     * clause.  If a SQL AS is not specified, the value returned from
     * getColumnLabel will be the same as the value returned by the
     * getColumnName method.
     *
     * @param column the first column is 1, the second is 2, ...
     * @return the suggested column title
     * @exception SQLException if a database access error occurs
     */
    String getColumnLabel(int column) throws SQLException;

后面的過程就和昨天講的方案一一模一樣了,不再贅述。

方案三-ResultMap

resultMap 元素是 MyBatis 中最重要最強大的元素。它就是讓你遠離 90%的需要從結(jié)果 集中取出數(shù)據(jù)的 JDBC 代碼的那個東西, 而且在一些情形下允許你做一些 JDBC 不支持的事 情。 事實上, 編寫相似于對復(fù)雜語句聯(lián)合映射這些等同的代碼, 也許可以跨過上千行的代碼。 ResultMap 的設(shè)計就是簡單語句不需要明確的結(jié)果映射,而很多復(fù)雜語句確實需要描述它們 的關(guān)系。
ResultMap是Mybatis中可以完成復(fù)雜語句映射的東西,但在我們的日常開發(fā)中,我們往往是一個XML對應(yīng)JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 對象),并沒有特別復(fù)雜的應(yīng)用,下面也是基于日常的使用,看看簡單的ResultMap在源碼層面是如何展現(xiàn)的。


        
        
        
        

在resultMap的子元素result對應(yīng)了result和對象字段之間的映射,并通過id標(biāo)示,你在Select語句中指定需要使用的resultMap即可。
源碼層面的話,依舊在DefaultResultSetHandler的handleResultSets中處理返回集合。

List resultMaps = mappedStatement.getResultMaps(); 

在這次的ResultMap中,相比之前方案,其屬性更加的豐富起來。將之前寫的Result的信息保存在了resultMappings,idResultMappings等中,以備后續(xù)使用。

后續(xù)的函數(shù)走向和方案一二一致,在創(chuàng)建自動映射的時候出現(xiàn)了不同。

privateList createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix)throwsSQLException { 

在這個函數(shù)中,會獲取沒有映射過的列名。

final List unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix); 

之后會根據(jù)resultMap查看是否有未映射的字段。

loadMappedAndUnmappedColumnNames(resultMap, columnPrefix); 
List mappedColumnNames = new ArrayList();
    List unmappedColumnNames = new ArrayList();
    final String upperColumnPrefix = columnPrefix == null ? null : columnPrefix.toUpperCase(Locale.ENGLISH);
    // 這里沒有配置前綴,根據(jù)之前的圖,定義了ResultMap后,會記錄這些已經(jīng)配置映射的字段。
    final Set mappedColumns = prependPrefixes(resultMap.getMappedColumns(), upperColumnPrefix);
    for (String columnName : columnNames) {
      // 遍歷列名,如果在已映射的配置中,那么就加入已經(jīng)映射的列名數(shù)據(jù),
      final String upperColumnName = columnName.toUpperCase(Locale.ENGLISH);
      if (mappedColumns.contains(upperColumnName)) {
        mappedColumnNames.add(upperColumnName);
      } else {
        unmappedColumnNames.add(columnName);
      }
    }
    // 生成未映射和已映射的Map
    mappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), mappedColumnNames);
    unMappedColumnNamesMap.put(getMapKey(resultMap, columnPrefix), unmappedColumnNames);

如果有沒配置在ResultMap中,且Select出來的,那么之后也會按照之前方案一那樣,繼續(xù)往下走,去對象中尋找映射關(guān)系。
由于沒有未映射的字段,使用自動映射的結(jié)果是false。

foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; 

之后繼續(xù)往下走,使用applyPropertyMappings來創(chuàng)建對象。使用了PropertyMapping。里面包含了字段名,列名,字段的類型和對應(yīng)的處理器。

遍歷整個Mappings。

Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix); 

函數(shù)里主要的就是獲取這個字段對應(yīng)的類型處理器,防止類型轉(zhuǎn)換失敗,這一部分下次會專門看一下。

final TypeHandler typeHandler = propertyMapping.getTypeHandler();
final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
return typeHandler.getResult(rs, column);

TypeHandler就是一個接口,主要完成的工作就是從Result根據(jù)列名,獲取相應(yīng)類型的值,為下一步反射賦值做準(zhǔn)備。至于它是怎么決定為什么用這個類型的TypeHandler下次再看。最后就是給對應(yīng)字段賦值。

metaObject.setValue(property, value); 

最后就完成了整個類的賦值。

總結(jié)

大致上,Mybatis完成映射主要是兩種方式。

只根據(jù)列名,利用自動映射,根據(jù)反射類的信息,得到列名和字段之間的關(guān)系,使用對應(yīng)的TypeHandler,完成字段的賦值。

使用ResultMap預(yù)先定義好映射關(guān)系,也是最后根據(jù)TypeHandler和反射,完成字段的賦值。
我個人感覺就簡單的用法來說,兩者都可以,在一次會話中,Configuration中的ResultMap關(guān)系建立好,在每一次查詢的時候就不用再去重新建立了,直接用就行。而自動映射的話,執(zhí)行過一次后,也會在會話中建立自動映射的緩存。所以沒什么差別。但如果復(fù)雜的映射的話,就非ResultMap莫屬啦。具體可以參考Mybatis文檔關(guān)于映射的章節(jié),因為目前用不到比較復(fù)雜的映射, 不做深究了。

http://www.mybatis.org/mybati...

下次去看一下Mybatis是如何知道數(shù)據(jù)庫中的數(shù)據(jù)和字段應(yīng)該用什么樣的類型轉(zhuǎn)換器的。

如果你想了解更多,歡迎關(guān)注我的微信公眾號。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67415.html

相關(guān)文章

  • Mybatis系列源碼角度理解Mybatis字段映射-駝峰式命名

    摘要:主要有三種方案駝峰式命名開關(guān),或者不開,數(shù)據(jù)庫列和字段名全一致。開啟開配置項后,在匹配時,能夠根據(jù)數(shù)據(jù)庫列名找到對應(yīng)對應(yīng)的駝峰式命名后的字段。經(jīng)過若干次中途崩潰,我終于寫完了駝峰式命名開關(guān)下,我們是如何完成數(shù)據(jù)庫列和字段名的映射的。 在上篇博客-[[JDBC] 處理ResultSet,構(gòu)建Java對象](https://my.oschina.net/kailun...中提到,我們需要分...

    qiangdada 評論0 收藏0
  • MyBatis理解與掌握(關(guān)聯(lián)查詢)

    摘要:訂單信息與訂單明細為一對多關(guān)系。例如先從單表查詢,需要時再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫性能,因為查詢單表要比關(guān)聯(lián)查詢多張表速度要快。作用將關(guān)聯(lián)查詢信息映射到一個對象中。 MyBatis理解與掌握(關(guān)聯(lián)查詢) @(MyBatis)[Java, 框架, MyBatis] 一對一查詢 案例:查詢所有訂單信息,關(guān)聯(lián)查詢下單用戶信息 showImg(https://segmentfault...

    MiracleWong 評論0 收藏0
  • Mybatis系列源碼角度理解Mybatis的數(shù)據(jù)轉(zhuǎn)換器TypeHandler

    摘要:無論是在預(yù)處理語句中設(shè)置一個參數(shù)時,還是從結(jié)果集中取出一個值時,都會用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成類型。這個抽象類實現(xiàn)了接口,這個接口主要定義了類型轉(zhuǎn)換的幾種操作。至于這個抽象類繼承的,主要是提供了獲取這個具體是哪個類型。 TypeHandlers 無論是 MyBatis 在預(yù)處理語句(PreparedStatement)中設(shè)置一個參數(shù)時,還是從結(jié)果集中取出一個值時, 都會用...

    Edison 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<