MyBatis的動態SQL應該這麼寫


對於還沒有入門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組裝。


在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章