1.mybatis默認支持使用ognl表達式來生成動態sql語句
MyBatis中可以使用OGNL的地方有兩處:
- 動態SQL表達式中
- ${param}參數中
上面這兩處地方在MyBatis中處理的時候都是使用OGNL處理的。
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select>
如果這些條件沒有一個能匹配上將會怎樣?最終這條 SQL 會變成這樣:
SELECT * FROM BLOG WHERE
這會導致查詢失敗。如果僅僅第二個條件匹配又會怎樣?這條 SQL 最終會是這樣:
SELECT * FROM BLOG WHERE AND title like ‘yiibai.com’
這個查詢也會失敗。這個問題不能簡單的用條件句式來解決,如果你也曾經被迫這樣寫過,那么你很可能從此以后都不想再這樣去寫了。
MyBatis 有一個簡單的處理,這在90%的情況下都會有用。而在不能使用的地方,你可以自定義處理方式來令其正常工作。一處簡單的修改就能得到想要的效果:
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
where 元素知道只有在一個以上的if條件有值的情況下才去插入“WHERE”子句。而且,若最后的內容是“AND”或“OR”開頭的,where 元素也知道如何將他們去除。
如果 where 元素沒有按正常套路出牌,我們還是可以通過自定義 trim 元素來定制我們想要的功能。比如,和 where 元素等價的自定義 trim 元素為:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
今天遇到一個場景需要寫一個這樣的查詢語句:
用戶對象userInfo包含下面幾個字段:
userName phone email qqId weiboId wxId
現在新注冊用戶,傳過來一個注冊userInfo對象,現在要到數據庫中驗證狀態status=1 (表示激活的用戶)的用戶中,是否存在一個用戶,只要它這些字段中至少有一個與新注冊的對象對應的字段內容相同,那就說明重復注冊。
翻譯成sql語句表示一下的意思大概就是:
select * from tablename where
(
userName=”xxx”
or phone =”xxx”
or …
)
and status=1
一開始我是這樣寫的,在mybatis中的代碼就是這樣:
<select id="selectBySelective" resultType="xxx.UserInfo"> select <include refid="Base_Column_List" /> from uc_user <where> (<if test="userName != null" > user_name = #{userName} </if> <if test="email != null" > or email = #{email} </if> <if test="phone != null" > or phone = #{phone} </if> <if test="weiboId != null" > or weibo_id = #{weiboId} </if> <if test="wxId != null" > or wx_id = #{wxId} </if> <if test="qqId != null" > or qq_id = #{qqId} </if>) </where> and status = 1 </select>
這樣代碼看似沒有什么問題但是其實是有問題的。為什么呢?
如果userName 為空,后面某字段不為空,最后的sql語言會成為這樣:
select * from uc_user where(or email = "xxx") and status = 1
使用mybatis < where > 標簽就是為了防止這種情況,mybatis會在第一個
userName 為空的情況下,幫我們去掉后面的語句的第一個”or”
但是我加了where標簽中加入()后,語句會報錯。因為自動去掉”or”會失效。
查看了mybatis官方文檔發現了另一個標簽 < trim >可以通過自定義 trim 元素來定制我們想要的功能
trim標簽包圍的內容可以設置幾個屬性:
prefix :內容之前加的前綴
suffix :內容之后加的后綴
prefixOverrides: 屬性會忽略通過管道分隔的文本序列(注意此例中的空格也是必要的,多個忽略序列用“|”隔開)。它帶來的結果就是所有在 prefixOverrides 屬性中指定的內容將被移除。
所以我修改后的代碼是:
<select id="selectBySelective" resultType="xxx.UserInfo"> select <include refid="Base_Column_List" /> from uc_user <trim prefix="WHERE (" suffix=")" prefixOverrides="AND |OR "> <if test="userName != null" > user_name = #{userName} </if> <if test="email != null" > or email = #{email} </if> <if test="phone != null" > or phone = #{phone} </if> <if test="weiboId != null" > or weibo_id = #{weiboId} </if> <if test="wxId != null" > or wx_id = #{wxId} </if> <if test="qqId != null" > or qq_id = #{qqId} </if> </trim> and status = 1 </select>
ok搞定。
- <select id="getStudentList_if" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">
- SELECT ST.STUDENT_ID,
- ST.STUDENT_NAME,
- ST.STUDENT_SEX,
- ST.STUDENT_BIRTHDAY,
- ST.STUDENT_PHOTO,
- ST.CLASS_ID,
- ST.PLACE_ID
- FROM STUDENT_TBL ST
- WHERE
- <if test="studentName !=null ">
- ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')
- </if>
- <if test="studentSex != null and studentSex != '' ">
- AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}
- </if>
- <if test="studentBirthday != null ">
- AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}
- </if>