對於還沒有入門MyBatis的童鞋,這裏建議看這篇博客:mybatis入門看這一篇就夠了
動態SQL元素
動態SQL是MyBatis的強大特性之一,MyBatis 3 採用了功能強大的基於OGNL的表達式來完成動態的SQL,他消除了之前版本中需要了解的大多數元素,使用不到原來一半的元素就可以完成所需的工作。
MyBatis動態SQL中的主要元素如下表所示:
元素 | 說明 |
---|---|
if | 判斷語句,用於單條件分支判斷 |
choose、when、otherwise | 相當於Java中的switch…case…default語句,用於多條件分支判斷 |
where、trim、set | 輔助元素,用於處理一些SQL拼裝、特殊字符問題 |
foreach | 循環語句,常用於in語句等列舉條件中 |
bind | 從OGNL表達式中創建一個變量,並將其綁定到上下文,常用於模糊查詢的sql中 |
if 元素
在MyBatis中,<if>
元素是最常用的判斷語句,它類似於Java中的 if 語句,主要用於實現某些簡單的條件選擇。
接下來在映射文件中使用<if>
元素
<!-- <if>元素使用 -->
<select id="findCustomerByNameAndJobs" parameterType="Customer" resultType="Customer">
select * from t_customer where 1=1
<if test="username !=null and username !=''">
and username like concat('%',#{username},'%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</select>
在上述代碼中,使用<if>
元素的 test 屬性分別對username和jobs進行了非空判斷,如果傳入的查詢條件非空就進行動態SQL組裝。(test屬性多用於條件判斷語句,用於判斷真假,大部分的場景中都是進行非空判斷,有時候也需要判斷字符串、數字和枚舉等)
choose、when、otherwise 元素
在使用<if>
元素時,只要test屬性中的表達式爲true,就會執行元素中的條件語句,但是在實際應用中,有時只需多個元素中選擇一個去執行。
例如下面的場景:
當客戶名稱不爲空,則只根據客戶名稱進行客戶篩選;
當客戶名稱爲空,而客戶職業不爲空,則只根據客戶職業進行客戶篩選;
當客戶名稱和客戶職業都爲空,則需要查詢所有電話不爲空的客戶信息;
對於這種情況,<if>
元素就顯得有些雞肋。那麼針對上面這種情況,MyBatis中可以使用<choose>、<when>、<otherwise>
元素進行處理。
接下來在映射文件中使用這三個元素
<!--<choose>(<when>、<otherwise>)元素使用 -->
<select id="findCustomerByNameOrJobs" parameterType="Customer" resultType="Customer">
select * from t_customer where 1=1
<choose>
<when test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</when>
<when test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
</select>
在上述代碼中,使用了<choose>
元素進行SQL拼裝,當第一個<when>
元素中的條件爲真,則只動態組裝第一個<when>
元素中的SQL片段,否則向下繼續判斷第二個<when>
的條件是否爲真,以此類推。當所有的<when>
中的條件均爲假時,則只會組裝<otherwise>
元素內的SQL片段。
where、trim 元素
在上面兩個示例中,編寫的SQL後面都加入了“where 1=1”的條件,因爲這樣纔可以保證SQL語法正確。那麼有沒有什麼方法不添加“1=1”的條件也能使拼接後的SQL成立呢?針對這種情況可以用<where>
元素來處理。
接下來在映射文件中使用<where>
元素
<!-- <where>元素 -->
<select id="findCustomerByNameAndJobs" parameterType="Customer" resultType="Customer">
select * from t_customer
<where>
<if test="username !=null and username !=''">
and username like concat('%',#{username},'%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</where>
</select>
上述代碼中,使用<where>
元素對“where 1=1”條件進行了替換,<where>
元素會自動判斷組合條件下拼裝的SQL語句,只有<where>
元素內的條件成立時,纔會拼接SQL中加入的where關鍵字,否則將不會添加。
除了使用<where>
元素外,還可以通過<trim>
元素來制定需要的功能,上述代碼還可以修改爲如下形式:
<!-- <trim>元素 -->
<select id="findCustomerByNameAndJobs" parameterType="Customer" resultType="Customer">
select * from t_customer
<trim prefix="where" prefixOverrides="and">
<if test="username !=null and username !=''">
and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=''">
and jobs= #{jobs}
</if>
</trim>
</select>
上述代碼中,<trim>
元素的prefix屬性代表的是語句的前綴(這裏指的是用where來連接後面的SQL片斷),而prefixOverrides屬性代表的是需要去除的那些特殊字符串(這裏定義了要去除的SQL中的and)。
set 元素
<set>
元素主要用於更新操作,其主要的作用是在動態包含的SQL語句前輸出一個SET關鍵字,並將SQL語句中最後一個多餘的逗號去除。
接下來在映射文件中使用<set>
元素
<!-- <set>元素 -->
<update id="updateCustomer" parameterType="Customer">
update t_customer
<set>
<if test="username !=null and username !=''">
username=#{username},
</if>
<if test="jobs !=null and jobs !=''">
jobs=#{jobs},
</if>
<if test="phone !=null and phone !=''">
phone=#{phone},
</if>
</set>
where id=#{id}
</update>
上述代碼中,使用<set>
元素和<if>
元素相結合的方式組裝update語句。當傳入的更新字段非空時,就將此字段進行動態SQL組裝,並更新該字段,否則字段不執行更新操作。
foreach 元素
MyBatis中提供了一種用於數組和集合循環遍歷的方式,就是<foreach>
元素。使用<foreach>
元素的好處就是不需要每次查詢都向數據庫發送查詢SQL,提高了查詢效率。<foreach>
元素通常在構建IN條件語句時使用。
接下來在映射文件中使用<foreach>
元素
<!--<foreach>元素使用 -->
<select id="findCustomerByIds" parameterType="List"
resultType="Customer">
select * from t_customer where id in
<foreach item="id" index="index" collection="list" open="("
separator="," close=")">
#{id}
</foreach>
</select>
上述代碼中,元素裏添加了很多屬性,接下來對幾種屬性進行描述:
- item:循環中當前的元素
- index:當前元素在集合的位置下標
- collection:配置的 list 是傳遞過來的參數類型(首字母小寫),它可以是array、list、Map集合的鍵等
- open和close:配置以什麼符號將這些集合元素包裝起來
- separator:配置的是各個元素之間的間隔符
bind 元素
在進行模糊查詢編寫SQL語句的時候,如果使用“${}”進行字符串拼接的話, 無法防止SQL注入問題;如果使用concat函數進行拼接,則只針對mysql數據庫有效;如果使用的是oracle數據庫的話,則使用連接符號“||”。這樣的話,映射文件中的SQL就要根據不同的情況提供不同的形式來實現,不利於移植。爲此,MyBatis提供了<bind>
元素來解決此問題。
接下來在映射文件中使用<bind>
元素
<!--<bind>元素的使用:根據客戶名模糊查詢客戶信息 -->
<select id="findCustomerByName" parameterType="Customer" resultType="Customer">
<!--_parameter.getUsername()也可直接寫成傳入的字段屬性名,即username -->
<bind name="pattern_username" value="'%'+_parameter.getUsername()+'%'" />
select * from t_customer
where
username like #{pattern_username}
</select>
上述代碼中,使用<bind>
元素定義了一個name爲pattern_username的變量,<bind>
元素中value的屬性值就是拼接的查詢字符串,其中_parameter.getUsername()(也可以寫成userame)表示傳遞進來的參數。在SQL語句中,直接引用<bind>
元素的name屬性值即可進行動態SQL組裝。