摘要:北京解決辦法在字段的時(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 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 中最重要最強(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中處理返回集合。
ListresultMaps = mappedStatement.getResultMaps();
在這次的ResultMap中,相比之前方案,其屬性更加的豐富起來。將之前寫的Result的信息保存在了resultMappings,idResultMappings等中,以備后續(xù)使用。
后續(xù)的函數(shù)走向和方案一二一致,在創(chuàng)建自動(dòng)映射的時(shí)候出現(xiàn)了不同。
privateListcreateAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix)throwsSQLException {
在這個(gè)函數(shù)中,會(huì)獲取沒有映射過的列名。
final ListunmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
之后會(huì)根據(jù)resultMap查看是否有未映射的字段。
loadMappedAndUnmappedColumnNames(resultMap, columnPrefix);
ListmappedColumnNames = 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è)類的賦值。
大致上,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ù)雜的映射, 不做深究了。
下次去看一下Mybatis是如何知道數(shù)據(jù)庫中的數(shù)據(jù)和字段應(yīng)該用什么樣的類型轉(zhuǎn)換器的。http://www.mybatis.org/mybati...
如果你想了解更多,歡迎關(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),或者不開,數(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...中提到,我們需要分...
摘要:訂單信息與訂單明細(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...
摘要:無論是在預(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ì)用...
閱讀 2980·2021-11-16 11:45
閱讀 5125·2021-09-22 10:57
閱讀 1763·2021-09-08 09:36
閱讀 1585·2021-09-02 15:40
閱讀 2508·2021-07-26 23:38
閱讀 1184·2019-08-30 15:55
閱讀 923·2019-08-30 15:54
閱讀 1213·2019-08-29 14:06