mybatis有一個強大的特性,其餘框架在拼接sql的時候要特別謹慎,好比哪裏須要空格,還要注意去掉列表最後一個列名的逗號,mybtis的動態sql能夠幫助咱們逃離這樣的痛苦掙扎,那就是動態SQL.它還能夠處理一種狀況,當你不肯定你的參數不知道是否是爲空的時候,咱們不須要在業務邏輯中判斷,直接在sql中處理,代碼無比簡潔。主要的動態sql標籤以下:
java
注意事項:
在mapper中若是出現大於號(>),小於號(),大於等於號(),小於等於號()等,最好須要轉換成爲實體符號,這是由於mapper是XML文件,xml文件自己就含有較多的<>這樣的尖括號,因此解析的時候可能會解析出錯。sql
原符號 | < | <= | > | >= | & | ' | " |
---|---|---|---|---|---|---|---|
替換符號 | < |
<= |
> |
>= |
& |
' |
" |
咱們常常須要根據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>標籤,在有查詢語句的時候,自動補上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裏面是不規範的,那咱們能夠經過
下面這樣的是錯誤的,當傳入的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>
有時候,咱們只想去匹配第一個條件,或者第一個條件不匹配的時候纔會去匹配第二個條件,不像<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。
動態SQL要有一個比較多的操做是對一個集合進行遍歷,一般是在構建IN條件語句的時候。須要注意的點:
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標籤裏面複用,在其餘地方複用的時候須要使用<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語句規範便可。
【做者簡介】:
秦懷,公衆號【秦懷雜貨店】做者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。這個世界但願一切都很快,更快,可是我但願本身能走好每一步,寫好每一篇文章,期待和大家一塊兒交流。