Mybatis 處理列名—字段名映射(一) :駝峰式命名映射

我們需要分析Mybatis在轉(zhuǎn)換Result到需要的Java業(yè)務(wù)對象時做的三件事搔课,如下:

[JDBC] 處理ResultSet,構(gòu)建Java對象

https://my.oschina.net/kailuncen/blog/906992

解決了數(shù)據(jù)庫列名到Java列名的映射。

解決了數(shù)據(jù)庫類型到Java類型的轉(zhuǎn)換工作截亦。

在轉(zhuǎn)換過程中具備一定的容錯能力爬泥。

其實核心就是:

數(shù)據(jù)庫中的列名怎么和對象中的字段對應(yīng)起來。

數(shù)據(jù)庫中的列的類型怎么轉(zhuǎn)換到合適的Java類型崩瓤,不引起轉(zhuǎn)換失敗袍啡。

今天我們先來看第一點,數(shù)據(jù)庫中的列名怎么和對象中的字段對應(yīng)起來却桶。首先是日常PO(Persistant Object) CityPO,里面有五個字段境输。

public class CityPO {

Integer id;

Long cityId;

String cityName;

String cityEnName;

String cityPyName;

本次要查詢的數(shù)據(jù)庫中的列名如下所示。

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ù)庫中的列名對應(yīng)到了對象的字段名嗅剖。如下是Mybatis的接口類和映射文件。

public interface CityMapper {

CityPO selectCity(int id);

}


PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

select id,city_id,city_name,city_en_name from SU_City where id = #{id}

在上面的映射文件中嘁扼,namespace指定了這個接口類的全限定類名信粮,緊隨其后的select代表是select語句沛硅,id是接口類中函數(shù)的名字鸟赫,resultType代表了從這條語句中返回的期望類型的類的完全限定名或別名,在此例子中是我們的業(yè)務(wù)對象CityPO的類路徑剑肯。

主要有三種方案

駝峰式命名開關(guān)莲绰,或者不開欺旧,數(shù)據(jù)庫列和字段名全一致。

Select時指定AS蛤签。

resultMap 最穩(wěn)健。

這篇主要看一下第一種栅哀,附上示例和部分源碼走讀震肮。

1.駝峰命名開關(guān)称龙。

因為CityPO的列名是完全根據(jù)數(shù)據(jù)庫列名駝峰式命名后得到的,因此Mybatis提供了一個配置項戳晌。開啟開配置項后鲫尊,在匹配時,能夠根據(jù)數(shù)據(jù)庫列名找到對應(yīng)對應(yīng)的駝峰式命名后的字段沦偎。


我們從源碼角度解讀一下疫向,Mybat處理ResultSet的映射默認(rèn)都在DefaultResultSetHandler中完成。

處理行數(shù)據(jù)的時候的時候主要在下面的函數(shù)里進(jìn)行豪嚎,由于我們在映射文件中沒有定義額外的ResultMap搔驼,因此會直接進(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ù)如下舌涨,在這里完成了對象的生成及賦值。

Object rowValue = getRowValue(rsw, discriminatedResultMap);

在這里先創(chuàng)建了對象的實例扔字,然后獲取了對象的元信息囊嘉,為反射賦值做準(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完成了整個過程革为,我們進(jìn)去探一探扭粱。

就是下面這個函數(shù)創(chuàng)建好了映射關(guān)系,這個函數(shù)的下半部分是完成賦值的震檩,映射的部分下次會詳細(xì)分析焊刹。

List autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);

在這個方法里,上半部分是生成了數(shù)據(jù)庫的列名恳蹲,在這個函數(shù)中找到了對應(yīng)的字段名虐块。

final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());

我們進(jìn)去看一看,它傳進(jìn)了生成好的數(shù)據(jù)庫列名嘉蕾,傳進(jìn)了前面提到的是否根據(jù)駝峰式命名映射開關(guān)的值贺奠。

事實證明,真的很簡單错忱,往下看儡率,就是把下劃線都去了。

public String findProperty(String name, boolean useCamelCaseMapping) {

if (useCamelCaseMapping) {

name = name.replace("_", "");

}

return findProperty(name);

}

隱隱覺得是不是大小寫不敏感啊以清,繼續(xù)往下看儿普,這里返回找到的字段名。

private StringBuilder buildProperty(String name, StringBuilder builder) {

..........

String propertyName = reflector.findPropertyName(name);

if (propertyName != null) {

builder.append(propertyName);

}

}

return builder;

}

好了掷倔,真相大白眉孩,就是大小寫不敏感的。

public String findPropertyName(String name) {

return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));

}

所以如果你數(shù)據(jù)庫里字段是city_id,city_Id,大寫I,那么可能會有問題吧浪汪,不過仔細(xì)想想巴柿,誰會吃力不討好干這種事情,硬要處理成標(biāo)準(zhǔn)的駝峰式命名也可以啦死遭,不過感覺必要性不大广恢。

經(jīng)過若干次中途崩潰,我終于寫完了駝峰式命名開關(guān)下呀潭,我們是如何完成數(shù)據(jù)庫列和字段名的映射的钉迷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钠署,隨后出現(xiàn)的幾起案子糠聪,更是在濱河造成了極大的恐慌,老刑警劉巖踏幻,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枷颊,死亡現(xiàn)場離奇詭異,居然都是意外死亡该面,警方通過查閱死者的電腦和手機夭苗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隔缀,“玉大人题造,你說我怎么就攤上這事』常” “怎么了界赔?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牵触。 經(jīng)常有香客問我淮悼,道長,這世上最難降的妖魔是什么揽思? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任袜腥,我火速辦了婚禮,結(jié)果婚禮上钉汗,老公的妹妹穿的比我還像新娘羹令。我一直安慰自己,他們只是感情好损痰,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布福侈。 她就那樣靜靜地躺著,像睡著了一般卢未。 火紅的嫁衣襯著肌膚如雪肪凛。 梳的紋絲不亂的頭發(fā)上堰汉,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音显拜,去河邊找鬼衡奥。 笑死爹袁,一個胖子當(dāng)著我的面吹牛远荠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播失息,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼譬淳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盹兢?” 一聲冷哼從身側(cè)響起邻梆,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绎秒,沒想到半個月后浦妄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡见芹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年剂娄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玄呛。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡阅懦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出徘铝,到底是詐尸還是另有隱情耳胎,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布惕它,位于F島的核電站怕午,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淹魄。R本人自食惡果不足惜郁惜,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揭北。 院中可真熱鬧扳炬,春花似錦、人聲如沸搔体。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疚俱。三九已至劝术,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背养晋。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工衬吆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绳泉。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓逊抡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親零酪。 傳聞我的和親對象是個殘疾皇子冒嫡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容