MyBatis動(dòng)態(tài)sql

if

if 標(biāo)簽通常用于 WHE阻 語句中,通過判斷參數(shù)值來決定是否使用某個(gè)查詢條件,它也經(jīng)常用于 UPDATE 語句中判斷是否更新某一個(gè)字段 , 還可以在 INSERT 語句中用來判斷是否插入某個(gè)字段的值。

if 標(biāo)簽有一個(gè)必填的屬性 test, test 的屬性值是一個(gè)符合 OGNL 要求的判斷表達(dá)式,表達(dá)式的結(jié)果可以是 true 或 false 沧踏,除此之外所有的非 0值都為 true ,只有0為 false 稀余。 為了方便理解悦冀,在表達(dá)式中 ,建議只用 true 或 false 作為結(jié)果 睛琳。

  • 判斷條件 property ! =nu ll 或 property == null : 適用于任何類型的宇段 盒蟆,用于判斷屬性值是否為空踏烙。
  • 判斷條件 property != '' 或 prope rty == '': 僅適用于 String 類型的宇段 ,用于判斷是否為空字符串 历等。
  • and 和 or :當(dāng)有多個(gè)判斷條件時(shí)讨惩,使用 and 或 or 進(jìn)行連接,嵌套的判斷可以使用小括號(hào)分組寒屯, and 相當(dāng)于
    Java 中的與(&&)荐捻, or 相當(dāng)于 Java 中的或 (||)。
    上面兩個(gè)條件的屬性類型都是 String寡夹,對字符串的判斷和 Java 中的判斷類似处面,首先需要判斷字段是否為 null ,然后再去判斷是否為空(在 OGNL 表達(dá)式中 菩掏,這兩個(gè)判斷的順序不會(huì)影響判斷的結(jié)果魂角,也不會(huì)有空指針異常)。在本章所有例子中智绸,字符串的判斷幾乎都包含 null和空的判斷野揪,這兩個(gè)條件不是必須寫在一起,可以根據(jù)實(shí)際業(yè)務(wù)決定是否需要空值判斷 瞧栗。

choose when otherwise

if 標(biāo)簽提供了基本的條件判斷斯稳,但是它無法實(shí)現(xiàn) if. . . else 、 if ... else ...的邏輯迹恐,要想實(shí)現(xiàn)這樣的邏輯挣惰,就需用到 choose when otherwise 標(biāo)簽。
choose 元素中包含 when和 otherwise 兩個(gè)標(biāo)簽系草,一個(gè) choose 中至少有一個(gè) when 通熄,有 0 個(gè)或者1 個(gè)
otherwise 唆涝。在己有的 sys_user 表中找都,除了主鍵 id 外,我們認(rèn)為 user_name (用戶名)也是唯一的廊酣,所有的用戶名都不可以重復(fù) 能耻。 現(xiàn)在進(jìn)行如下查詢:
當(dāng)參數(shù) id 有值的時(shí)候優(yōu)先使用 id 查詢,當(dāng) id 沒有值時(shí)就去判斷用戶名是否有值亡驰,如果有值就用用戶名查詢 晓猛,如果用 戶名也沒有值,就使 SQL 查詢無結(jié)果 凡辱。

<select id=” selectByidOrUserName” resultType=” tk.mybatis.simple.m0del. SysUser” >
  select id,
    user_name,
    user_password,
    user_email,
    user_info
  from sys_ user
  where 1 = 1
  <choose >
    <when test=” id != null ” >
        and id= #{id}
    </when >
    <when test=” u serName != null and userName !=””>
      and user name = #{userName}
    </when>
    <otherwise>
      and 1 = 2
    </otherwise>
  </choose>
</ select>

在以上查詢中戒职,如果沒有 otherwise 這個(gè)限制條件,所有的用戶都會(huì)被查詢出來透乾,因?yàn)?br> 我們在對應(yīng) 的接口方法中使用了 Sys User 作為返回值洪燥,所以當(dāng)實(shí)際查詢結(jié)果是多個(gè)時(shí)就會(huì)報(bào)
錯(cuò)磕秤。 添加 otherwise 條件后,由于 where 條件不滿足捧韵,因此在這種情況下就查詢不到結(jié)果市咆。

where

這 3 個(gè)標(biāo)簽解決了類似的問題,并且 where 和 set 都屬于 trim 的一種具體用法再来。下面分別來看這 3 個(gè)標(biāo)簽蒙兰。
where 標(biāo)簽的作用:如果該標(biāo)簽包含的元素中有返回值,就插入一個(gè) where ;如果 where后面的字符串是以 AND 和 OR 開頭的挎塌,就將它們剔除凤巨。

<select id=” selectByUser” resultType=” tk . mybatis . simple . model . SysUser” >
*
from sys_user
<where>
  <if test=”userName != null and userName !=””>
    and user_name like concat ( ’ %’,#{userName} 痹雅, ’ % ’)
  </ if>
  <if test=”userEmail ! = ” and userEmail != null ”>
    and user email = #{userEmail}
  </ if>
</where>
</select >

當(dāng) if 條件都不滿足的時(shí)候, where 元素中沒有內(nèi)容糊识,所以在 SQL 中不會(huì)出現(xiàn) where 绩社, 如果 if 條件滿足, where 元素的內(nèi)容就是以 and 開頭的條件赂苗, where 會(huì)自動(dòng)去掉開頭的 and愉耙,這也能保證 where 條件正確 。這種情況下生成的 SQL 更干凈拌滋、更貼切朴沿,不會(huì)在任何情況下都有 where 1 = 1 這樣的條件 。

set

set 標(biāo)簽的作用:如果該標(biāo)簽包含的元素中有返回值败砂,就插入一個(gè) set :如果 set 后面的字符串是 以逗號(hào)結(jié)尾的赌渣,就將這個(gè)逗號(hào)剔除 。

<update id=”updateByidSelective ” >
    update sys_user
    <set>
        <if test=” userName != null and userName !=””>
            user name= #{userName} ,
        </ if>
        <if test=” userPassword != null and userPassword ! = ””>
            user password= #{userPassword} ,
        </if>
        <if test=”userEmail != null and userEmail != ””>
            user email = #{userEmail} ,
        </ if>
        <i f test=” userinfo != null and userinfo !=””>
            user info = #{userinfo},
        </if>
        <if test=”headimg != null ” >
            head_img = #{headimg, jdbcType=BLOB},
        </if >
        <if test=”createTime != nul l ”>
            create_time = #{createTime, jdbcType=TIMESTAMP},
        </if>
    id = # {id} ,
    </set>
    where id = #{id}
</ update>

在 set 標(biāo)簽的用法中 昌犹, SQL 后面的逗號(hào)沒有問題了坚芜,但是如果 set 元素中沒有內(nèi)容,照樣
會(huì)出現(xiàn) SQL 錯(cuò)誤斜姥,所以為了避免錯(cuò)誤產(chǎn)生鸿竖,類似 id = #{id }這樣必然存在的賦值仍然有保留
的必要。從這一點(diǎn)來看铸敏, set 標(biāo)簽并沒有解決全部的問題缚忧,使用時(shí)仍然需要注意。

trim

where 和 set 標(biāo)簽 的功能都可以用 trim 標(biāo)簽來實(shí)現(xiàn)杈笔,并且在底層就是通過TrimSqlNode 實(shí)現(xiàn)的 闪水。
where 標(biāo)簽對應(yīng) trim 的實(shí)現(xiàn)如下。

<trim prefix=”WHERE ” prefixOverrides=”AND IOR ” >
    ......
</ trim>

這里的 AND 和 OR 后面的空格不能省略蒙具,為了避免匹配到 andes 球榆、 orders 等單詞 峰弹。
實(shí)際的 prefixeOverrides 包含“AND”、“OR”芜果、“AND\n ”鞠呈、“OR\n ”、“AND\r”右钾、OR\r”蚁吝、“AND\t ”、 “ OR \t ”舀射, 不僅僅是上面提到的兩個(gè)帶空格的前綴 窘茁。
set 標(biāo)簽對應(yīng) 的 trim 實(shí)現(xiàn)如下 。

<trim prefix=” SET” suf f ixOverrides=”, ” >
  .....
</ trim>

trim 標(biāo)簽有如下屬性脆烟。
prefix :當(dāng) trim 元素內(nèi)包含內(nèi)容時(shí)山林,會(huì)給內(nèi)容增加 prefix 指定的前綴。
prefixOverrides :當(dāng) trim 元素內(nèi)包含內(nèi)容時(shí)邢羔,會(huì)把內(nèi)容中匹配的前綴字符串去掉驼抹。
suffix :當(dāng) trim 元素內(nèi)包含內(nèi)容時(shí),會(huì)給內(nèi)容增加 suffix 指定的后綴拜鹤。
suffixOverrides :當(dāng) trim 元素內(nèi)包含內(nèi)容時(shí)框冀,會(huì)把內(nèi)容中匹配的后綴字符串去掉。

foreach

SQL 語句中有時(shí)會(huì)使用 IN 關(guān)鍵字敏簿,例如 id in ( 1 , 2 , 3 )明也。可以使用${ids}方式直接獲取值惯裕,但這種寫法不能防止 SQL 注入温数,想避免 SQL 注入就需要用#{}的方式,這時(shí)就要配合使用 foreach 標(biāo)簽來滿足需求蜻势。
foreach 可以對數(shù)組撑刺、 Map 或?qū)崿F(xiàn)了工 terable 接口(如 List 、 Set )的對象進(jìn)行遍歷咙边。數(shù)組在處理時(shí)會(huì)轉(zhuǎn)換為 List 對象猜煮,因此 foreach 遍歷的對象可以分為兩大類 : Iterable類型和 Map 類型

foreach 實(shí)現(xiàn) in 集合(或數(shù)組)是最簡單和常用的一種情況
<foreach collection=” lis t ” open=” (” close=” )” separator=” , ” item=” id” index=” i ” >
    #{id}
</foreach>

foreach 包含以下屬性。

  • collection : 必填败许,值為要選代循環(huán)的屬性名。這個(gè)屬性值的情況有很多淑蔚。
  • item:變量名市殷,值為從法代對象中取出的每一個(gè)值。
  • index :索引的屬性名刹衫,在集合數(shù)組情況下值為當(dāng)前索引值 醋寝,當(dāng)選代循環(huán)的對象是 Map類型時(shí)搞挣,這個(gè)值為 Map 的 key (鍵值)。
  • open:整個(gè)循環(huán)內(nèi)容開頭的字符串 音羞。
  • close : 整個(gè)循環(huán)內(nèi)容結(jié)尾的字符串囱桨。
  • separator :每次循環(huán)的分隔符 。

bind

bind 標(biāo)簽可以使用 OGNL 表達(dá)式創(chuàng)建一個(gè)變量井將其綁定到上下文中嗅绰。在前面的例子中舍肠,UserMapper.xml 有一個(gè) selectByUser 方法,這個(gè)方法用到了 like 查詢條件窘面,部分代碼如下 翠语。

<if test=” userNarne != null and userNarne ! = ””>
    and user name like concat ( ’ % ’, #{ userNarne }财边,’ % ’ )
</if>

使用 con cat 函數(shù)連接字符串肌括,在 MySQL 中,這個(gè)函數(shù)支持多個(gè)參數(shù)酣难,但在 Oracle 中只支持兩個(gè)參數(shù)谍夭。由于不 同數(shù)據(jù)庫之間的語法差異 ,如果更換數(shù)據(jù)庫憨募,有些 SQL 語句可能就需要重寫慧库。針對這種情況,可 以使用 bind 標(biāo)簽來避免由于更換數(shù)據(jù)庫帶來的一些麻煩馋嗜。將上面的
方法改為 bind 方式后齐板,代碼如下。

<if test=” userNarne != null and userNarne !=””>
    <bind narne= " userNarneLike ” value = '%'+ userNarne + '%'/>
    and user name like #{userNarneLike}
</if>

bind 標(biāo)簽的兩個(gè)屬性都是必選項(xiàng)葛菇, name 為綁定到上下文的變量名甘磨, value 為 OGNL 表
達(dá)式。創(chuàng)建一個(gè) bind 標(biāo)簽的變量后 眯停,就可以在下面直接使用济舆,使用 bind 拼接字符串不僅可
以避免因更換數(shù)據(jù)庫而修改 SQL,也能預(yù)防 SQL 注入莺债。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末滋觉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子齐邦,更是在濱河造成了極大的恐慌椎侠,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件措拇,死亡現(xiàn)場離奇詭異我纪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門浅悉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來趟据,“玉大人,你說我怎么就攤上這事术健⌒诩睿” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵荞估,是天一觀的道長咳促。 經(jīng)常有香客問我,道長泼舱,這世上最難降的妖魔是什么等缀? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮娇昙,結(jié)果婚禮上尺迂,老公的妹妹穿的比我還像新娘。我一直安慰自己冒掌,他們只是感情好噪裕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著股毫,像睡著了一般膳音。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铃诬,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天祭陷,我揣著相機(jī)與錄音,去河邊找鬼趣席。 笑死兵志,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宣肚。 我是一名探鬼主播想罕,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼霉涨!你這毒婦竟也來了按价?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤笙瑟,失蹤者是張志新(化名)和其女友劉穎楼镐,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逮走,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸠蚪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年今阳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了师溅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茅信。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖墓臭,靈堂內(nèi)的尸體忽然破棺而出蘸鲸,到底是詐尸還是另有隱情,我是刑警寧澤窿锉,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布酌摇,位于F島的核電站,受9級(jí)特大地震影響嗡载,放射性物質(zhì)發(fā)生泄漏窑多。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一洼滚、第九天 我趴在偏房一處隱蔽的房頂上張望埂息。 院中可真熱鬧,春花似錦遥巴、人聲如沸千康。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拾弃。三九已至,卻和暖如春摆霉,著一層夾襖步出監(jiān)牢的瞬間豪椿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工携栋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搭盾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓刻两,卻偏偏與公主長得像增蹭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子磅摹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

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