摘要:主要有三種方案駝峰式命名開(kāi)關(guān),或者不開(kāi),數(shù)據(jù)庫(kù)列和字段名全一致。開(kāi)啟開(kāi)配置項(xiàng)后,在匹配時(shí),能夠根據(jù)數(shù)據(jù)庫(kù)列名找到對(duì)應(yīng)對(duì)應(yīng)的駝峰式命名后的字段。經(jīng)過(guò)若干次中途崩潰,我終于寫(xiě)完了駝峰式命名開(kāi)關(guān)下,我們是如何完成數(shù)據(jù)庫(kù)列和字段名的映射的。
在上篇博客-[[JDBC] 處理ResultSet,構(gòu)建Java對(duì)象](https://my.oschina.net/kailun...中提到,我們需要分析Mybatis在轉(zhuǎn)換Result到需要的Java業(yè)務(wù)對(duì)象時(shí)做的三件事,如下:
解決了數(shù)據(jù)庫(kù)列名到Java列名的映射。
解決了數(shù)據(jù)庫(kù)類(lèi)型到Java類(lèi)型的轉(zhuǎn)換工作。
在轉(zhuǎn)換過(guò)程中具備一定的容錯(cuò)能力。
其實(shí)核心就是:
數(shù)據(jù)庫(kù)中的列名怎么和對(duì)象中的字段對(duì)應(yīng)起來(lái)。
數(shù)據(jù)庫(kù)中的列的類(lèi)型怎么轉(zhuǎn)換到合適的Java類(lèi)型,不引起轉(zhuǎn)換失敗。
今天我們先來(lái)看第一點(diǎn),數(shù)據(jù)庫(kù)中的列名怎么和對(duì)象中的字段對(duì)應(yīng)起來(lái)。首先是日常PO(Persistant Object) CityPO,里面有五個(gè)字段。
public class CityPO { Integer id; Long cityId; String cityName; String cityEnName; String cityPyName;
本次要查詢(xún)的數(shù)據(jù)庫(kù)中的列名如下所示。
mysql> mysql> desc SU_City; +--------------+-------------+------+-----+-------------------+-----------------------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+-------------------+-----------------------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | city_id | int(11) | NO | UNI | NULL | | | city_name | varchar(20) | NO | | | | | city_en_name | varchar(20) | NO | | | | | city_py_name | varchar(50) | NO | | | | | create_time | datetime | NO | | CURRENT_TIMESTAMP | | | updatetime | datetime | NO | MUL | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +--------------+-------------+------+-----+-------------------+-----------------------------+ 7 rows in set (0.01 sec)
我們是按照駝峰式命名,把數(shù)據(jù)庫(kù)中的列名對(duì)應(yīng)到了對(duì)象的字段名。如下是Mybatis的接口類(lèi)和映射文件。
public interface CityMapper { CityPO selectCity(int id); }
在上面的映射文件中,namespace指定了這個(gè)接口類(lèi)的全限定類(lèi)名,緊隨其后的select代表是select語(yǔ)句,id是接口類(lèi)中函數(shù)的名字,resultType代表了從這條語(yǔ)句中返回的期望類(lèi)型的類(lèi)的完全限定名或別名,在此例子中是我們的業(yè)務(wù)對(duì)象CityPO的類(lèi)路徑。
主要有三種方案
駝峰式命名開(kāi)關(guān),或者不開(kāi),數(shù)據(jù)庫(kù)列和字段名全一致。
Select時(shí)指定AS。
resultMap 最穩(wěn)健。
這篇主要看一下第一種,附上示例和部分源碼走讀。
駝峰命名開(kāi)關(guān)。
因?yàn)镃ityPO的列名是完全根據(jù)數(shù)據(jù)庫(kù)列名駝峰式命名后得到的,因此Mybatis提供了一個(gè)配置項(xiàng)。開(kāi)啟開(kāi)配置項(xiàng)后,在匹配時(shí),能夠根據(jù)數(shù)據(jù)庫(kù)列名找到對(duì)應(yīng)對(duì)應(yīng)的駝峰式命名后的字段。
我們從源碼角度解讀一下,Mybat處理ResultSet的映射默認(rèn)都在DefaultResultSetHandler中完成。
處理行數(shù)據(jù)的時(shí)候的時(shí)候主要在下面?的函數(shù)里進(jìn)行,由于我們?cè)谟成湮募袥](méi)有定義額外的ResultMap,因此會(huì)直接進(jìn)入else分支的代碼。
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { if (resultMap.hasNestedResultMaps()) { ensureNoRowBounds(); checkResultHandler(); handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } }
進(jìn)入handleRowValuesForSimpleResultMap中,主要處理函數(shù)如下,在這里完成了對(duì)象的生成及賦值。
Object rowValue = getRowValue(rsw, discriminatedResultMap);
在這里先創(chuàng)建了對(duì)象的實(shí)例,然后獲取了對(duì)象的元信息,為反射賦值做準(zhǔn)備。
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException { final ResultLoaderMap lazyLoader = new ResultLoaderMap(); Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null); if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) { final MetaObject metaObject = configuration.newMetaObject(rowValue); boolean foundValues = this.useConstructorMappings; if (shouldApplyAutomaticMappings(resultMap, false)) { foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues; } foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues; foundValues = lazyLoader.size() > 0 || foundValues; rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null; } return rowValue; }
在applyAutomaticMappings完成了整個(gè)過(guò)程,我們進(jìn)去探一探。
就是下面這個(gè)函數(shù)創(chuàng)建好了映射關(guān)系,這個(gè)函數(shù)的下半部分是完成賦值的,映射的部分下次會(huì)詳細(xì)分析。
ListautoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
在這個(gè)方法里,上半部分是生成了數(shù)據(jù)庫(kù)的列名,在這個(gè)函數(shù)中找到了對(duì)應(yīng)的字段名。
final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
我們進(jìn)去看一看,它傳進(jìn)了生成好的數(shù)據(jù)庫(kù)列名,傳進(jìn)了前面提到的是否根據(jù)駝峰式命名映射開(kāi)關(guān)的值。
事實(shí)證明,真的很簡(jiǎn)單,往下看,就是把下劃線都去了。
public String findProperty(String name, boolean useCamelCaseMapping) { if (useCamelCaseMapping) { name = name.replace("_", ""); } return findProperty(name); }
隱隱覺(jué)得是不是大小寫(xiě)不敏感啊,繼續(xù)往下看,這里返回找到的字段名。
private StringBuilder buildProperty(String name, StringBuilder builder) { .......... String propertyName = reflector.findPropertyName(name); if (propertyName != null) { builder.append(propertyName); } } return builder; }
好了,真相大白,就是大小寫(xiě)不敏感的。
public String findPropertyName(String name) { return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH)); }
所以如果你數(shù)據(jù)庫(kù)里字段是city_id,city_Id,大寫(xiě)I,那么可能會(huì)有問(wèn)題吧,不過(guò)仔細(xì)想想,誰(shuí)會(huì)吃力不討好干這種事情,硬要處理成標(biāo)準(zhǔn)的駝峰式命名也可以啦,不過(guò)感覺(jué)必要性不大。
經(jīng)過(guò)若干次中途崩潰,我終于寫(xiě)完了駝峰式命名開(kāi)關(guān)下,我們是如何完成數(shù)據(jù)庫(kù)列和字段名的映射的。后面的博文會(huì)繼續(xù)看看后續(xù)兩種方案以及DDL時(shí)對(duì)象字段是如何賦值到Sql語(yǔ)句中。
如果想進(jìn)一步了解的話(huà),歡迎關(guān)注我的微信公眾號(hào)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/67416.html
摘要:北京解決辦法在字段的時(shí)候使用,下面是改動(dòng)后的映射文件。北京那么我們來(lái)看看它是如何生效的,主要的代碼在哪里。源碼層面的話(huà),依舊在的中處理返回集合??偨Y(jié)大致上,完成映射主要是兩種方式。使用預(yù)先定義好映射關(guān)系,也是最后根據(jù)和反射,完成字段的賦值。 前言 考慮到在Select時(shí)使用AS和方案一其實(shí)沒(méi)什么差別,在介紹ResultMap之前,順便帶過(guò)一下。 方案二-Select .... AS 當(dāng)...
摘要:無(wú)論是在預(yù)處理語(yǔ)句中設(shè)置一個(gè)參數(shù)時(shí),還是從結(jié)果集中取出一個(gè)值時(shí),都會(huì)用類(lèi)型處理器將獲取的值以合適的方式轉(zhuǎn)換成類(lèi)型。這個(gè)抽象類(lèi)實(shí)現(xiàn)了接口,這個(gè)接口主要定義了類(lèi)型轉(zhuǎn)換的幾種操作。至于這個(gè)抽象類(lèi)繼承的,主要是提供了獲取這個(gè)具體是哪個(gè)類(lèi)型。 TypeHandlers 無(wú)論是 MyBatis 在預(yù)處理語(yǔ)句(PreparedStatement)中設(shè)置一個(gè)參數(shù)時(shí),還是從結(jié)果集中取出一個(gè)值時(shí), 都會(huì)用...
摘要:一級(jí)緩存介紹及相關(guān)配置。在這個(gè)章節(jié),我們學(xué)習(xí)如何使用的一級(jí)緩存。一級(jí)緩存實(shí)驗(yàn)配置完畢后,通過(guò)實(shí)驗(yàn)的方式了解一級(jí)緩存的效果。源碼分析了解具體的工作流程后,我們隊(duì)查詢(xún)相關(guān)的核心類(lèi)和一級(jí)緩存的源碼進(jìn)行走讀。 我,后端Java工程師,現(xiàn)在美團(tuán)點(diǎn)評(píng)工作。愛(ài)健身,愛(ài)技術(shù),也喜歡寫(xiě)點(diǎn)文字。個(gè)人網(wǎng)站: http://kailuncen.me公眾號(hào): KailunTalk (凱倫說(shuō)) 前言 本文主要涉及...
摘要:一級(jí)緩存介紹及相關(guān)配置。在這個(gè)章節(jié),我們學(xué)習(xí)如何使用的一級(jí)緩存。一級(jí)緩存實(shí)驗(yàn)配置完畢后,通過(guò)實(shí)驗(yàn)的方式了解一級(jí)緩存的效果。源碼分析了解具體的工作流程后,我們隊(duì)查詢(xún)相關(guān)的核心類(lèi)和一級(jí)緩存的源碼進(jìn)行走讀。 我,后端Java工程師,現(xiàn)在美團(tuán)點(diǎn)評(píng)工作。愛(ài)健身,愛(ài)技術(shù),也喜歡寫(xiě)點(diǎn)文字。個(gè)人網(wǎng)站: http://kailuncen.me公眾號(hào): KailunTalk (凱倫說(shuō)) 前言 本文主要涉及...
閱讀 633·2023-04-25 21:29
閱讀 1194·2023-04-25 21:27
閱讀 1110·2021-11-25 09:43
閱讀 1173·2021-09-29 09:43
閱讀 3685·2021-09-03 10:30
閱讀 2924·2019-08-29 15:26
閱讀 2882·2019-08-29 12:52
閱讀 1809·2019-08-29 11:10