国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

Zhuxy / 3011人閱讀

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

前言

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

方案二-Select .... AS

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

不過在這次,我們對(duì)PO做了小小的改動(dòng),把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字段的時(shí)候使用AS,下面是改動(dòng)后的映射文件。

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

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

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

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

在這個(gè)構(gòu)造函數(shù)當(dāng)中,我們會(huì)獲取數(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));
}

在添加列名時(shí),會(huì)從配置中獲取是否使用類標(biāo)簽,isUseColumnLabel,默認(rèn)為true。根據(jù)Javadoc,這個(gè)ColumnLabel就是AS后的那個(gè)名字,如果沒有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 中最重要最強(qiáng)大的元素。它就是讓你遠(yuǎn)離 90%的需要從結(jié)果 集中取出數(shù)據(jù)的 JDBC 代碼的那個(gè)東西, 而且在一些情形下允許你做一些 JDBC 不支持的事 情。 事實(shí)上, 編寫相似于對(duì)復(fù)雜語句聯(lián)合映射這些等同的代碼, 也許可以跨過上千行的代碼。 ResultMap 的設(shè)計(jì)就是簡單語句不需要明確的結(jié)果映射,而很多復(fù)雜語句確實(shí)需要描述它們 的關(guān)系。
ResultMap是Mybatis中可以完成復(fù)雜語句映射的東西,但在我們的日常開發(fā)中,我們往往是一個(gè)XML對(duì)應(yīng)JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 對(duì)象),并沒有特別復(fù)雜的應(yīng)用,下面也是基于日常的使用,看看簡單的ResultMap在源碼層面是如何展現(xiàn)的。


        
        
        
        

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

List resultMaps = mappedStatement.getResultMaps(); 

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

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

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

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

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

之后會(huì)根據(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后,會(huì)記錄這些已經(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出來的,那么之后也會(huì)按照之前方案一那樣,繼續(xù)往下走,去對(duì)象中尋找映射關(guān)系。
由于沒有未映射的字段,使用自動(dòng)映射的結(jié)果是false。

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

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

遍歷整個(gè)Mappings。

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

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

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

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

metaObject.setValue(property, value); 

最后就完成了整個(gè)類的賦值。

總結(jié)

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

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

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

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

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

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67415.html

相關(guān)文章

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

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

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

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

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

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

    Edison 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<