Mybatis【13】-- Mybatis動態Sql標籤的使用

mybatis有一個強大的特性,其餘框架在拼接sql的時候要特別謹慎,好比哪裏須要空格,還要注意去掉列表最後一個列名的逗號,mybtis的動態sql能夠幫助咱們逃離這樣的痛苦掙扎,那就是動態SQL.它還能夠處理一種狀況,當你不肯定你的參數不知道是否是爲空的時候,咱們不須要在業務邏輯中判斷,直接在sql中處理,代碼無比簡潔。主要的動態sql標籤以下:
java

  • <if></if>
  • <where></where>(trim,set)
  • <choose></choose>(when, otherwise)
  • <foreach></foreach>

注意事項:
在mapper中若是出現大於號(>),小於號(),大於等於號(),小於等於號()等,最好須要轉換成爲實體符號,這是由於mapper是XML文件,xml文件自己就含有較多的<>這樣的尖括號,因此解析的時候可能會解析出錯。sql

原符號 < <= > >= & ' "
替換符號 &lt; &lt;= &gt; &gt;= &amp; &apos; &quot;

<if>

咱們常常須要根據where後面的條件篩選出須要的數據,當多個條件拼接的時候,咱們通常使用<if></if>,若是if裏面的條件成立,那麼就會使用標籤的語句,可是咱們能夠知道where句子第一個標籤是沒有and的,然後面的條件都須要and,因此有一種作法是第一個使用where 1 = 1,這個條件恆成立,後面的全部子語句都加上and,若是增長判斷,那麼咱們只須要加<if>標籤就能夠了。數組

<!-- 動態sql if標籤-->
    <!-- &可使用and來代替 ,注意!=須要連在一塊兒寫-->
    <select id="selectStudentByDynamicSQL" resultType="Student">
        <!--最經常使用的(動態參數) select id,name,age,score from student where name like '%' #{name} '%' -->
        <!-- 下面的是字符串拼接 ,只能寫value,瞭解便可,容易sql注入,執行效率低,不建議使用-->
        select id,name,age,score
        from student
        where 1=1
        <if test="name != null and name != ''">
            and name like '%' #{name} '%'
        </if>
        <if test="age > 0">
            and age > #{age}
        </if>
    </select>

當有兩個查詢條件的時候,sql語句是:select * from student where 1=1 and name like '%' ? '%' and age > ?

當有一個查詢條件的時候:sql語句就變成:select * from student where 1=1 and name like '%' ? '%'

當沒有查詢條件的時候,sql語句是:
select * from student where 1=1

<if></if>標籤須要手動在where後面添加1=1語句,這是由於若是<if>後面的條件都是false的時候,where後面若是沒有1=1語句,sql就剩下一個空空的where,sql就會報錯。因此在where後面須要加上永真句子1=1,可是這樣有一個問題,當數據量比較大的時候,會嚴重影響sql的查詢效率。mybatis

<where></where>,<trim></trim>,<set></set>

使用<where></where>標籤,在有查詢語句的時候,自動補上where子句,在沒有查詢條件的時候,不會加上where子句,這也就解決了咱們上面所涉及到的問題,剩下的就是<if>標籤的and子句,第一個,<if>片斷裏面能夠不包含and,也能夠包含,系統會自動去掉and,可是其餘的<if>片斷裏面的and,必須寫上,不然會出錯。下面的寫法中,若是name爲null,第二個if標籤中的if也會被去掉,不會報錯。app

<select id="selectStudentByDynamicSQLWhere" resultType="Student">
        <!--最經常使用的(動態參數) select id,name,age,score from student where name like '%' #{name} '%' -->
        <!-- 下面的是字符串拼接 ,只能寫value,瞭解便可,容易sql注入,執行效率低,不建議使用-->
        select id,name,age,score
        from student
        <where>
            <if test="name != null and name != ''">
                and name like '%' #{name} '%'
            </if>
            <if test="age > 0">
                and age > #{age}
            </if>
        </where>
    </select>

若是where裏面是不規範的,那咱們能夠經過 來自定義where元素的功能, 標籤主要有如下屬性: 框架

  • prefix:在包含的內容前加上前綴,不是百分之百會加,會根據須要自動加
  • suffix:在包含的內容後面加上後綴,不是百分之百會加,會根據須要自動加
  • prefixOverrides:能夠把包含內容的首部某些內容忽略(不能本身增長),不必定會忽略,根據須要自動忽略
  • suffixOverrides:也能夠把包含內容的尾部的某些內容忽略(不能本身增長),同上

下面這樣的是錯誤的,當傳入的name不爲空,並且age大於0的時候ide

<select id="selectStudentByDynamicSQLWhere" resultType="Student">
        select id,name,age,score
        from student
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name != ''">
                name like '%' #{name} '%'
            </if>
            <if test="age > 0">
                age > #{age}
            </if>
        </trim>
    </select>

不會本身增長and在第二個age前面:



下面的是正確的,咱們在兩個<if>標籤前面都增長了and,第二個and會自動去掉:code

<select id="selectStudentByDynamicSQLWhere" resultType="Student">
        select id,name,age,score
        from student
        <trim prefix="where" prefixOverrides="and">
            <if test="name != null and name != ''">
                and name like '%' #{name} '%'
            </if>
            <if test="age > 0">
                and age > #{age}
            </if>
        </trim>
    </select>

下面是後綴模式, prefix="set"表示在整個語句前面加上前綴set, suffixoverride=","表示每個語句後面的後綴","能夠被忽略,若是是須要的話suffix=" where id = #{id}表示在整個語句後面增長where id = #{id},:xml

update user
<trim prefix="set" suffixoverride="," suffix=" where id = #{id} ">
  <if test="name != null and name.length()>0"> name=#{name} , </if>
  <if test="age != null "> age=#{age} ,  </if>
</trim>

固然,咱們對上面的語句還有動態解決的方案,那就是 標籤: 對象

<update id="updateStudent">
		update student
		<set>
            <!-- 第一個if標籤的逗號必定要有,最後一個標籤的逗號能夠沒有-->
            <if test="name != null"> name=#{name},</if>
            <if test="age != null">age=#{age},</if>
            <if test="score != null"> score=#{score},</if>
        </set>
         where id=#{id}
	</update>

<choose>, <when>, <otherwise>

有時候,咱們只想去匹配第一個條件,或者第一個條件不匹配的時候纔會去匹配第二個條件,不像<where></where>標籤裏面的<if></if>同樣會去判斷全部的子語句是否能夠匹配,而是遇到一個匹配的就會執行跳出<choose></choose>

<!-- 	selectStudentByDynamicSQLChoose 相似於switch,知足後就不會判斷後面的了-->
    <!-- 若是名字不爲空,那麼按照名字來查詢,若是名字爲空,就按照年齡來查詢,若是沒有查詢條件,就沒有查詢條件 -->
    <select id="selectStudentByDynamicSQLChoose" resultType="Student">
        <!--最經常使用的(動態參數) select id,name,age,score from student where name like '%' #{name} '%' -->
        select id,name,age,score
        from student
        <where>
            <choose>
                <when test="name != null and name != ''">
                    and name like '%' #{name} '%'
                </when>
                <when test="age > 0">
                    and age > #{age}
                </when>
                <otherwise>
                    and 1 != 1
                </otherwise>
            </choose>
        </where>
    </select>

<choose>標籤就像是switch語句,每個<when>都像是case,後面默認跟上break語句,只要知足一個就不會判斷後面的子語句了,當前面全部的<when></when>都不執行的時候,就會執行<otherwise></otherwise>標籤的內容,這個內容也就像是switch語句裏面的default。

foreach

動態SQL要有一個比較多的操做是對一個集合進行遍歷,一般是在構建IN條件語句的時候。須要注意的點:

  • collection 表示須要遍歷的集合類型,array表示須要遍歷的數組
  • open,close,separator是對遍歷內容的SQL拼接
  • foreach 元素的功能很是強大,它容許你指定一個集合,聲明能夠在元素體內使用的集合項(item)和索引(index)變量。它也容許你指定開頭與結尾的字符串以及在迭代結果之間放置分隔符。
  • 你能夠將任何可迭代對象(如 List、Set 等)、Map 對象或者數組對象傳遞給 foreach 做爲集合參數。當使用可迭代對象或者數組時,index 是當前迭代的次數,item 的值是本次迭代獲取的元素。當使用 Map 對象(或者 Map.Entry 對象的集合)時,index 是鍵,item 是值。

1.好比咱們須要查找學生的id爲1,2,3的學生信息,咱們不但願分開一次査一個,而是但願將數組id一次傳進去,查出來一個學生的集合。

sql接口能夠這樣寫,傳入一個對象的數組:

public List<Student>selectStudentByDynamicSQLForeachArray(Object[]studentIds);

sql語句以下,遍歷array數組的時候,指定左邊符號是左括號,右邊是右括號,元素以逗號分隔開:

<!-- select * from student where id in (1,3) -->
    <select id="selectStudentByDynamicSQLForeachArray" resultType="Student">
        select id,name,age,score
        from student
        <if test="array !=null and array.length > 0 ">
            where id in
            <foreach collection="array" open="(" close=")" item="myid" separator=",">
                #{myid}
            </foreach>
        </if>
    </select>

2.當遍歷的是一個類型爲int的list列表時:

public List<Student>selectStudentByDynamicSQLForeachList(List<Integer>studentIds);

sql語句以下,colleaction指定爲list:

<select id="selectStudentByDynamicSQLForeachList" resultType="Student">
        select id,name,age,score
        from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="myid" separator=",">
                #{myid}
            </foreach>
        </if>
    </select>

3.當遍歷的是一個類型爲對象的list:

public List<Student>selectStudentByDynamicSQLForeachListStudent(List<Student>students);

sql語句裏面與上面類似,只是在使用屬性的時候不太同樣:

<select id="selectStudentByDynamicSQLForeachListStudent" resultType="Student">
        select id,name,age,score
        from student
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="stu" separator=",">
                #{stu.id}
            </foreach>
        </if>
    </select>

<sql></sql>

用於定義sql片斷,方便在其餘SQL標籤裏面複用,在其餘地方複用的時候須要使用<include></include>子標籤,<sql>能夠定義sql的任何部分,因此<include>標籤能夠放在動態SQL的任何位置。

<sql id="selectHead">
		select id,name,age,score
		 from student
	</sql>
    <!-- 可讀性比較差 -->
    <select id="selectStudentByDynamicSQLfragment" resultType="Student">
        <include refid="selectHead"></include>
        <if test="list !=null and list.size > 0 ">
            where id in
            <foreach collection="list" open="(" close=")" item="stu" separator=",">
                #{stu.id}
            </foreach>
        </if>
    </select>

動態sql讓SQL寫起來更加簡潔,減小了不少重複代碼,動態sql之間能夠相互拼接,只要符合sql語句規範便可。

【做者簡介】
秦懷,公衆號【秦懷雜貨店】做者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。這個世界但願一切都很快,更快,可是我但願本身能走好每一步,寫好每一篇文章,期待和大家一塊兒交流。

相關文章
相關標籤/搜索