不學(xué)無(wú)數(shù)——Mybatis解析判斷表達(dá)式源碼分析

Mybatis解析判斷表達(dá)式源碼分析

在我們開(kāi)發(fā)過(guò)程中用Mybatis經(jīng)常會(huì)用到下面的例子

Mapper如下

Map<String ,String > testArray(@Param("array") String [] array);

XMl中的sql如下

<select id="testArray" resultType="map">
    select * from t_ams_ac_pmt_dtl where  cpt_pro=#{cptProp}
    <if test="array!=null and array != '' ">
        and cpt_pro=#{cptProp}
    </if>
</select>

剛看上面的代碼會(huì)覺(jué)得數(shù)組怎么能和空字符串進(jìn)行一起比較呢,一開(kāi)始會(huì)覺(jué)得這個(gè)代碼運(yùn)行起來(lái)絕對(duì)報(bào)錯(cuò),但是寫(xiě)單元測(cè)試運(yùn)行了一遍發(fā)現(xiàn)成功運(yùn)行了饵逐。因此想是不是Mybatis在內(nèi)部對(duì)數(shù)組類型的數(shù)據(jù)進(jìn)行了封裝砾跃。于是有了這一次的源碼解析之旅盹牧。上網(wǎng)查了查發(fā)現(xiàn)Mybatis解析使用了OGNL琼懊。至于什么是OGNL摘抄了百度百科中的一段話

OGNL是Object-Graph Navigation Language的縮寫(xiě)涌韩,它是一種功能強(qiáng)大的表達(dá)式語(yǔ)言熏版,通過(guò)它簡(jiǎn)單一致的表達(dá)式語(yǔ)法纷责,可以存取對(duì)象的任意屬性,調(diào)用對(duì)象的方法撼短,遍歷整個(gè)對(duì)象的結(jié)構(gòu)圖再膳,實(shí)現(xiàn)字段類型轉(zhuǎn)化等功能。它使用相同的表達(dá)式去存取對(duì)象的屬性曲横。這樣可以更好的取得數(shù)據(jù)喂柒。

單元測(cè)試類如下

    @Test
    public void testArray(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        TBapCheckPtsTranscdMapper mapper = sqlSession.getMapper(TBapCheckPtsTranscdMapper.class);
        String str= "1,2,3";
        String [] strings = str.split(",");
        mapper.testArray(strings);
    }

首先我們先來(lái)看一下DynamicSqlSource這個(gè)類,這個(gè)類中有個(gè)方法如下

  @Override
  public BoundSql getBoundSql(Object parameterObject) {
    DynamicContext context = new DynamicContext(configuration, parameterObject);
    rootSqlNode.apply(context);
    SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
    Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
    SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
    BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
    for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
      boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
    }
    return boundSql;
  }

其中

rootSqlNode.apply(context);

這段代碼對(duì)SQL進(jìn)行了動(dòng)態(tài)的拼接禾嫉,然后點(diǎn)進(jìn)去看一下

 @Override
  public boolean apply(DynamicContext context) {
    for (SqlNode sqlNode : contents) {
      sqlNode.apply(context);
    }
    return true;
  }

這里的SQL拼接運(yùn)用了組合模式不同的sqlNode調(diào)用的方法不一樣灾杰,但是最后的想要結(jié)果都是一樣的:拼接SQL。例如我們第一次進(jìn)apply這個(gè)方法中的時(shí)候他跳轉(zhuǎn)到了
StaticTextSqlNode這個(gè)類中調(diào)用了下面的方法

  @Override
  public boolean apply(DynamicContext context) {
    context.appendSql(text);
    return true;
  }

直接將SQL拼接為

select * from t_ams_ac_pmt_dtl where  cpt_pro=#{cptProp}

然后我們第二次循環(huán)執(zhí)行發(fā)現(xiàn)它跳轉(zhuǎn)到了IfSqlNode這個(gè)類中熙参,這是標(biāo)簽為<if>的判斷類艳吠,

  @Override
  public boolean apply(DynamicContext context) {
    if (evaluator.evaluateBoolean(test, context.getBindings())) {
      contents.apply(context);
      return true;
    }
    return false;
  }

在解析語(yǔ)句中傳了兩個(gè)參數(shù)進(jìn)去

evaluator.evaluateBoolean(test, context.getBindings())

  • test:就是要解析的表達(dá)式,在此場(chǎng)景下就是array!=null and array != ''
  • context.getBindings():獲得的是一個(gè)Map孽椰,其中存儲(chǔ)了參數(shù)array的所對(duì)應(yīng)的值昭娩,如下所示
image

然后接下來(lái)就到了OGNL解析表達(dá)式了凛篙,發(fā)現(xiàn)最后到了ASTNotEq這類中

    protected Object getValueBody(OgnlContext context, Object source) throws OgnlException {
        Object v1 = this._children[0].getValue(context, source);
        Object v2 = this._children[1].getValue(context, source);
        return OgnlOps.equal(v1, v2) ? Boolean.FALSE : Boolean.TRUE;
    }

這里解析分為了兩步進(jìn)行解析,上面的表達(dá)式為array!=null and array != ''那么他會(huì)根據(jù)and 進(jìn)行分組將其放入Node數(shù)組中栏渺。

  • Node[0]array!=null
  • Node[1]array != ''

然后這里面的兩個(gè)參數(shù)v1v2分別為左邊和右邊的參數(shù)呛梆,此時(shí)先解析Node[0]中的參數(shù)

  • v1:就是參數(shù)array對(duì)應(yīng)的數(shù)組的值
  • v2:就是null

此時(shí)到這應(yīng)該就知道為什么String數(shù)組為什么能和空字符串進(jìn)行比較了,因?yàn)樗麑?shù)組轉(zhuǎn)化為了Object然后用自己寫(xiě)的equal方法進(jìn)行比較磕诊。然后進(jìn)去他寫(xiě)的equal方法中看了以后發(fā)現(xiàn)他對(duì)數(shù)組比較是特殊的填物。

  • 如果左邊是數(shù)組右邊是字符串:兩個(gè)都轉(zhuǎn)換為Object然后進(jìn)行v1.getClass()==v2.getClass()判斷
  • 如果左邊是數(shù)組右邊也是數(shù)組:先判斷兩個(gè)數(shù)組的長(zhǎng)度是否相同,如果相同霎终,那么循環(huán)遍歷兩個(gè)數(shù)組進(jìn)行里面的值的比較
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匣掸,一起剝皮案震驚了整個(gè)濱河市陨闹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖沮峡,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荔睹,死亡現(xiàn)場(chǎng)離奇詭異镐依,居然都是意外死亡甩挫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)炮障,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)目派,“玉大人,你說(shuō)我怎么就攤上這事胁赢∑蟛洌” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵智末,是天一觀的道長(zhǎng)谅摄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)系馆,這世上最難降的妖魔是什么送漠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮由蘑,結(jié)果婚禮上闽寡,老公的妹妹穿的比我還像新娘。我一直安慰自己尼酿,他們只是感情好爷狈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著裳擎,像睡著了一般涎永。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天土辩,我揣著相機(jī)與錄音支救,去河邊找鬼抢野。 笑死拷淘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的指孤。 我是一名探鬼主播启涯,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼恃轩!你這毒婦竟也來(lái)了结洼?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤叉跛,失蹤者是張志新(化名)和其女友劉穎松忍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體筷厘,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸣峭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酥艳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摊溶。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖充石,靈堂內(nèi)的尸體忽然破棺而出莫换,到底是詐尸還是另有隱情,我是刑警寧澤骤铃,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布拉岁,位于F島的核電站,受9級(jí)特大地震影響惰爬,放射性物質(zhì)發(fā)生泄漏喊暖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一补鼻、第九天 我趴在偏房一處隱蔽的房頂上張望哄啄。 院中可真熱鬧,春花似錦风范、人聲如沸咨跌。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锌半。三九已至,卻和暖如春寇漫,著一層夾襖步出監(jiān)牢的瞬間刊殉,已是汗流浹背殉摔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留记焊,地道東北人逸月。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像遍膜,于是被迫代替她去往敵國(guó)和親碗硬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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

  • 1 Mybatis入門(mén) 1.1 單獨(dú)使用jdbc編程問(wèn)題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,306評(píng)論 0 38
  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis 瓢颅? MyBatis 是支持定制化 SQL恩尾、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 5,511評(píng)論 0 4
  • 思量南潯六月中。竹傘微傾挽懦,空守橋東翰意。寧候趖西盼君留,情知無(wú)期信柿,宛轉(zhuǎn)難收冀偶。 數(shù)載冰輪和淚流。霜染青絲角塑,對(duì)鏡妝樓蔫磨。黃泉...
    阿宅大人冬安閱讀 353評(píng)論 8 7
  • 01 這兩天堤如,有一個(gè)顏值與實(shí)力并存的人刷屏了。 這次是90后的小哥哥窒朋,年紀(jì)輕輕搀罢,已經(jīng)是副教授了。沒(méi)錯(cuò)侥猩,就是網(wǎng)傳湖南...
    院長(zhǎng)X大叔閱讀 567評(píng)論 2 14
  • 淡淡的回憶榔至,濃濃的情義, 十八年來(lái)欺劳,各自奔波唧取, 時(shí)光虧欠了良好的相聚, 縱然光陰如箭飛划提, 即使風(fēng)云變幻枫弟、物是人非,...
    Ahxin閱讀 362評(píng)論 0 3