Mybatis結(jié)果集自動(dòng)映射的實(shí)例代碼
在使用Mybatis時(shí),有的時(shí)候我們可以不用定義resultMap,而是直接在<select>語(yǔ)句上指定resultType。這個(gè)時(shí)候其實(shí)就用到了Mybatis的結(jié)果集自動(dòng)映射。Mybatis的自動(dòng)映射默認(rèn)是開(kāi)啟的,有需要我們也可以將其關(guān)閉(還可以調(diào)整自動(dòng)映射的策略)。
1 Mybatis結(jié)果集自動(dòng)映射
在使用Mybatis時(shí),有的時(shí)候我們可以不用定義resultMap,而是直接在<select>語(yǔ)句上指定resultType。這個(gè)時(shí)候其實(shí)就用到了Mybatis的結(jié)果集自動(dòng)映射。Mybatis的自動(dòng)映射默認(rèn)是開(kāi)啟的,其在映射的時(shí)候會(huì)先把沒(méi)有在resultMap中定義字段映射的字段按照名稱相同的方式自動(dòng)映射到返回類型的對(duì)應(yīng)屬性上。自動(dòng)映射的時(shí)候會(huì)忽略大小寫(xiě),比如查詢語(yǔ)句中查詢出來(lái)了一個(gè)字段是ID,我們對(duì)應(yīng)的返回類型有一個(gè)屬性id,且有一個(gè)setId()方法,那么id跟ID也是可以匹配的,是可以自動(dòng)映射的,Mybatis就會(huì)把查詢出來(lái)的結(jié)果集中字段ID對(duì)應(yīng)的值賦給返回類型對(duì)象的id屬性。
1.1 源碼分析
關(guān)于自動(dòng)映射這塊的邏輯規(guī)則可以參考Mybatis的DefaultResultSetHandler的源碼,其核心代碼如下。
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { List<UnMappedColumAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix); boolean foundValues = false; if (autoMapping.size() > 0) { for (UnMappedColumAutoMapping mapping : autoMapping) { final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); if (value != null || configuration.isCallSettersOnNulls()) { if (value != null || !mapping.primitive) { metaObject.setValue(mapping.property, value); } foundValues = true; } } } return foundValues; } private List<UnMappedColumAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException { final String mapKey = resultMap.getId() + ":" + columnPrefix; List<UnMappedColumAutoMapping> autoMapping = autoMappingsCache.get(mapKey); if (autoMapping == null) { autoMapping = new ArrayList<UnMappedColumAutoMapping>(); final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix); for (String columnName : unmappedColumnNames) { String propertyName = columnName; if (columnPrefix != null && !columnPrefix.isEmpty()) { if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) { propertyName = columnName.substring(columnPrefix.length()); } else { continue; } } final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase()); if (property != null && metaObject.hasSetter(property)) { final Class<?> propertyType = metaObject.getSetterType(property); if (typeHandlerRegistry.hasTypeHandler(propertyType)) { final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName); autoMapping.add(new UnMappedColumAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive())); } } } autoMappingsCache.put(mapKey, autoMapping); } return autoMapping; }
在上面的源碼中createAutomaticMappings()方法中的下面這句就是獲取當(dāng)前查詢結(jié)果集中沒(méi)有在resultMap中映射的字段,以進(jìn)行自動(dòng)映射。詳情請(qǐng)參考完整的源碼。
final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
1.2 示例
現(xiàn)假設(shè)我們有一個(gè)User類,其有id、name、username、email、mobile屬性,然后有下面這樣一個(gè)查詢及其對(duì)應(yīng)的resultMap定義。我們可以看到我們查詢出來(lái)的有id、name、user_name、email和mobile字段,在resultMap中我們只配置了字段user_name對(duì)應(yīng)的是username屬性,其它的我們都沒(méi)配置,但是查詢出來(lái)的結(jié)果中User對(duì)象的id、name、username、email和mobile屬性都會(huì)有值,因?yàn)樗鼈儠?huì)被Mybatis以自動(dòng)映射策略進(jìn)行賦值。
<resultMap type="com.elim.learn.mybatis.model.User" id="BaseResult"> <result column="user_name" property="username"/> </resultMap> <select id="findById" resultMap="BaseResult" parameterType="java.lang.Long" > select id,name,username user_name,email,mobile from t_user where id=#{id} </select>
1.3 自動(dòng)映射策略
Mybatis的自動(dòng)映射策略默認(rèn)是開(kāi)啟的,而且默認(rèn)是只對(duì)非嵌套的resultMap進(jìn)行自動(dòng)映射。這是通過(guò)Mybatis的全局配置autoMappingBehavior參數(shù)配置的。它一共有三種取值,分別是NONE、PARTIAL和FULL。
l NONE表示不啟用自動(dòng)映射
l PARTIAL表示只對(duì)非嵌套的resultMap進(jìn)行自動(dòng)映射
l FULL表示對(duì)所有的resultMap都進(jìn)行自動(dòng)映射
<!-- 自動(dòng)映射類型,可選值為NONE、PARTIAL和FULL,參考AutoMappingBehavior枚舉 --> <setting name="autoMappingBehavior" value="PARTIAL"/>
除了全局的是否啟用自動(dòng)映射的配置外,還可以對(duì)特定的resultMap設(shè)置是否啟用自動(dòng)映射。這是通過(guò)resultMap的autoMapping屬性配置的,可選值是true和false。定義在resultMap上的autoMapping的優(yōu)先級(jí)比全局配置的優(yōu)先級(jí)更高。
1.4 resultType自動(dòng)映射分析
我們?cè)谥付ㄒ粋€(gè)查詢語(yǔ)句的返回結(jié)果時(shí),可以直接指定resultType,也可以是指定resultMap,然后由指定的resultMap的type屬性指定真實(shí)的返回類型。實(shí)際上,Mybatis的底層在對(duì)結(jié)果集進(jìn)行處理時(shí)都是通過(guò)resultMap進(jìn)行處理的。當(dāng)我們指定的是resultType時(shí),Mybatis內(nèi)部會(huì)生成一個(gè)空的resultMap,然后指定其對(duì)應(yīng)的type為我們指定的resultType類型。那這個(gè)時(shí)候之所以返回結(jié)果能自動(dòng)映射到resultType類型的對(duì)應(yīng)屬性上,就是上面介紹的Mybatis的自動(dòng)映射機(jī)制的作用。如果在這種情況下,我們把全局的自動(dòng)映射關(guān)閉了,那么Mybatis就不能自動(dòng)映射了,也就得不到我們需要的返回結(jié)果了。如下就是直接指定的resultType。
<select id="findById" resultType="com.elim.learn.mybatis.model.User" parameterType="java.lang.Long" > select id,name,username,email,mobile from t_user where id=#{id} </select>
Mybatis的mapper.xml文件的內(nèi)容是由XMLMapperBuilder解析的,而其中定義的Mapper語(yǔ)句(select、insert等)則是由XMLStatementBuilder解析的,解析后會(huì)生成一個(gè)MappedStatement。對(duì)于Select語(yǔ)句,其對(duì)應(yīng)的resultMap的解析的核心邏輯如下,更多信息請(qǐng)參考官方源碼。
private List<ResultMap> getStatementResultMaps( String resultMap, Class<?> resultType, String statementId) { resultMap = applyCurrentNamespace(resultMap, true); List<ResultMap> resultMaps = new ArrayList<ResultMap>(); if (resultMap != null) { String[] resultMapNames = resultMap.split(","); for (String resultMapName : resultMapNames) { try { resultMaps.add(configuration.getResultMap(resultMapName.trim())); } catch (IllegalArgumentException e) { throw new IncompleteElementException("Could not find result map " + resultMapName, e); } } } else if (resultType != null) { ResultMap inlineResultMap = new ResultMap.Builder( configuration, statementId + "-Inline", resultType, new ArrayList<ResultMapping>(), null).build(); resultMaps.add(inlineResultMap); } return resultMaps; }
以上所述是小編給大家介紹的Mybatis結(jié)果集自動(dòng)映射的實(shí)例代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Java實(shí)現(xiàn)圖片上傳至FastDFS入門教程
這篇文章主要介紹了Java實(shí)現(xiàn)圖片上傳至FastDFS入門教程,通過(guò)前端ajax提交圖片到后端,java處理服務(wù)器文件上傳至FastDFS文件服務(wù)器系統(tǒng),以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07Windows下使用Graalvm將Springboot應(yīng)用編譯成exe大大提高啟動(dòng)和運(yùn)行效率(推薦)
這篇文章主要介紹了Windows下使用Graalvm將Springboot應(yīng)用編譯成exe大大提高啟動(dòng)和運(yùn)行效率,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02使用jekins自動(dòng)構(gòu)建部署java maven項(xiàng)目的方法步驟
這篇文章主要介紹了使用jekins自動(dòng)構(gòu)建部署java maven項(xiàng)目的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01使用GSON庫(kù)將Java中的map鍵值對(duì)應(yīng)結(jié)構(gòu)對(duì)象轉(zhuǎn)換為JSON
GSON是由Google開(kāi)發(fā)并開(kāi)源的實(shí)現(xiàn)Java對(duì)象與JSON之間相互轉(zhuǎn)換功能的類庫(kù),這里我們來(lái)看一下使用GSON庫(kù)將Java中的map鍵值對(duì)應(yīng)結(jié)構(gòu)對(duì)象轉(zhuǎn)換為JSON的示例:2016-06-06java實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲(1)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單五子棋小游戲的第一部分,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01SpringBoot實(shí)現(xiàn)短信發(fā)送及手機(jī)驗(yàn)證碼登錄
本文主要介紹了SpringBoot實(shí)現(xiàn)短信發(fā)送及手機(jī)驗(yàn)證碼登錄,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Java8流式API將實(shí)體類列表轉(zhuǎn)換為視圖對(duì)象列表的示例
這篇文章主要介紹了Java8流式API將實(shí)體類列表轉(zhuǎn)換為視圖對(duì)象列表的示例,文中有相關(guān)的代碼示例供大家參考,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-11-11