摘要:北京解決辦法在字段的時候使用,下面是改動后的映射文件。北京那么我們來看看它是如何生效的,主要的代碼在哪里。源碼層面的話,依舊在的中處理返回集合??偨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 SQLAS
* clause. If a SQLAS
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;
后面的過程就和昨天講的方案一一模一樣了,不再贅述。
方案三-ResultMapresultMap 元素是 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中處理返回集合。
ListresultMaps = mappedStatement.getResultMaps();
在這次的ResultMap中,相比之前方案,其屬性更加的豐富起來。將之前寫的Result的信息保存在了resultMappings,idResultMappings等中,以備后續(xù)使用。
后續(xù)的函數(shù)走向和方案一二一致,在創(chuàng)建自動映射的時候出現(xiàn)了不同。
privateListcreateAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix)throwsSQLException {
在這個函數(shù)中,會獲取沒有映射過的列名。
final ListunmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
之后會根據(jù)resultMap查看是否有未映射的字段。
loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
ListmappedColumnNames = 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);
最后就完成了整個類的賦值。
大致上,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ù)雜的映射, 不做深究了。
下次去看一下Mybatis是如何知道數(shù)據(jù)庫中的數(shù)據(jù)和字段應(yīng)該用什么樣的類型轉(zhuǎn)換器的。http://www.mybatis.org/mybati...
如果你想了解更多,歡迎關(guān)注我的微信公眾號。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67415.html
摘要:主要有三種方案駝峰式命名開關(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...中提到,我們需要分...
摘要:訂單信息與訂單明細為一對多關(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...
摘要:無論是在預(yù)處理語句中設(shè)置一個參數(shù)時,還是從結(jié)果集中取出一個值時,都會用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成類型。這個抽象類實現(xiàn)了接口,這個接口主要定義了類型轉(zhuǎn)換的幾種操作。至于這個抽象類繼承的,主要是提供了獲取這個具體是哪個類型。 TypeHandlers 無論是 MyBatis 在預(yù)處理語句(PreparedStatement)中設(shè)置一個參數(shù)時,還是從結(jié)果集中取出一個值時, 都會用...
閱讀 2989·2021-11-16 11:45
閱讀 5188·2021-09-22 10:57
閱讀 1775·2021-09-08 09:36
閱讀 1602·2021-09-02 15:40
閱讀 2517·2021-07-26 23:38
閱讀 1203·2019-08-30 15:55
閱讀 929·2019-08-30 15:54
閱讀 1220·2019-08-29 14:06