使用Mybatis實現動態SQL
作者 : Stanley 羅昊
【轉載請注明出處和署名,謝謝!】
寫在前面:
*本章節適合有Mybatis基礎者觀看*
前置說明
我現在寫一個查詢全部的sql語句,這個對各位來說,想必應該是非常簡單,我舉個例子:
select * from studnet //查詢全部
我現在需求又變了。我現在要根據年齡進行查詢了,那是不是也依然很簡單:
select * from student where age = #{age} //根據年齡查詢學生
那么,我現在再來一個需求,根據年齡跟姓名來查:
select * from student where age = #{age} and name=#{name};
但是,我們仔細發現,我剛才在寫sql語句,就需要復制粘貼,那也就意味着,在這以上的sql語句是重復的,也就是說三個語句里,查詢的都是同一張表,只不過加了一些條件;
因此,我沒有必要寫三次,其實我們寫一次就夠了;
如果使用動態sql來實現的話,就非常方便,比如:
我第一次使用的時候,僅使用select * from student 僅僅的查詢全部,用於初始化
我第二次再去使用的時候 僅使用 where = age
我第三次再去使用的時候 就成了 where = age and name =name
可以靈活的控制sql語句,這就是動態sql;
可以設想一下,如果沒有動態sql,我們是不是一個功能模塊,就要寫三段sql語句,很顯然讓代碼變的非常臃腫不整潔,效率還低,所以,在正常的企業開發當中,動態sql用點居多!
動態SQL
那么,到底怎么實現呢?這個,就用到了mybatis xml文件中的動態標簽了;
首先,我們需要看一下查詢條件:本次業務涉及到查詢所有、根據學生年齡查詢、根據學生年齡並且根據學生姓名進行查詢;
查詢所有,因為要在頁面初始化中使用,所以頁面加載之后需要展示出來,另外那些條件,就是幾個篩選條件,可以利用他們滿足自己的查詢需要;
現在,我們就根據以上業務來完成一個動態sql;
在要進行查詢的xml文件中編寫:
<select id = "selectAllorbynameAndage" resultType = "Student"> select * from student where <if test = " name!= null and name!= ' ' ">//如果傳過來的student對象有name屬性,並且該屬性不為空,便執行次條件 student = #{name} </if> <if test = "age !=null and age != ' ' "> And student = #{age} </if> </select>
講解:
1.if:什么叫if,就是如果有這么怎辦,如果沒怎么怎么辦,在這里的意思就是,你現在查的時候,要是傳入了一個名字,那么,我就根據你傳過來的name進行查詢。
換句話說,如果你沒傳這個字段,那么是不是就不進入這個判斷了,也就代表你沒寫這個where一樣;
用意:我現在傳過來一個學生對象,如果這個學生對象包含了一個name屬性,且name屬性不為空,那么我就要把這個student = #{name}給加上
if后面的test里面就寫執行條件
2.我們現在除了name之外,是不是還有可能有age;
根據以上的業務,我們發現,也是有根據age進行查詢的,那么,我們僅需在下面跟上一個if里面來寫關於age的判決即可;
但是值得注意的是,本次編寫前面需要加上and;
and:為什么在加and呢?
我們可以設想一下,目前的sql語句是這樣的:
select * from student where name = #{name}
如果不加and的話,是不是就變成了:
select * from student where name = #{name}age = #{age}
這樣顯然是不對的,sql語法都出錯兩,所以需要在前面加上and,加上and之后就是合法的sql語句了:
select * from student where name = #{name}And age = #{age}
解決sql語句解釋失敗
那么,問題來了,以上寫的那種方案是,name 跟 age 必須全部存在,才可以生效,一旦不存在,那么就會報錯,我現在認定這個name時在時不在的情況;
我舉個例子,本次查詢,僅僅按照age查詢,這個時候,age傳過來了,但是name沒有傳過來,因為我只查詢age,肯定只用把age傳過來,這個時候,name拿不到值,就導致了這樣的sql語句:
select * from student where And age = #{age}
這就很明顯,sql語句怎么可能寫成這樣,這個and就非常令人厭煩,為什么會導致成這樣呢?
還記得我們寫的一個if標簽嗎?如果name = null and name = ‘ ’,我這條標簽就不去執行,一旦不去執行就變成以上那樣了,原本有name是這樣的:
select * from student where name = #{name}And age = #{age}
你現在name為空了,那就表明name = #{name}就消失了
這個and你也去不掉它,你一旦去掉了,又會造成另外一種sql語法非法,如何解決這個不協調的字段呢?
有兩種解決方案;
第一種:
<select id = "selectAllorbynameAndage" resultType = "Student"> select * from student where 1 = 1 <if test = " name!= null and name!= ' ' ">//如果傳過來的student對象有name屬性,並且該屬性不為空,便執行次條件 And student = #{name} </if> <if test = "age !=null and age != ' ' "> And student = #{age} </if> </select>
我把studnt = name前面也加了一個and,但是這樣做會導致本次sql語句不成立,沒關系,我在where后面加了一個 1 = 1,就代表永遠成立,也就是強制讓數據庫認下這個and;
第二種【最佳/推薦】:
<select id = "selectAllorbynameAndage" resultType = "Student"> select * from student <where> <if test = " name!= null and name!= ' ' ">//如果傳過來的student對象有name屬性,並且該屬性不為空,便執行次條件 And student = #{name} </if> <if test = "age !=null and age != ' ' "> And student = #{age} </if> </where> </select>
現在呢,我們直接用where標簽把sql包裹,把主查詢后面的where就刪掉,因為已經不需要了,那么加上這個where標簽后,sql變成什么樣子了呢?
select * from student <where> and name = #{name}and age = #{age}
這樣的sql語句看似是不是像是那種有問題的sql語句,因為在where后面就有and,但是沒關心,不用管,這個<where>標簽是智能的,它會自動處理第一個and,不會處理第二個;
什么意思呢?就是本次查詢,如果你需要這個and,那么我就給你加上,如果你不需要這個and,我就不給你加,很顯然,本次查詢不需要這個and,所以就沒給你加;
這個時候,你把第一個and給刪了,再去執行,你會發現跟沒刪一樣,如果你加上這個and,你就會發現,跟沒加一樣,就是這么智能,非常便捷;
但是,如果你把第二個或往后的and刪了,就會出問題了,因為它只會幫你處理第第一個and;
所以,原理是這樣的:
剛才我說了,如果沒有name,那么第一個if就會消失,緊接着,age是不是就頂替name了,那么age就是第一個了
<select id = "selectAllorbynameAndage" resultType = "Student"> select * from student <where> <if test = "age !=null and age != ' ' "> And student = #{age} </if> </where> </select>
那么這個智能where標簽恰到好處的把第一個and給消掉了,從而完成了根據age查詢;
了解以上概念后,我們就把上面的業務給全部寫完吧,如果age跟name均不為空,那么我就根據這兩個進行查詢;
<select id = "selectAllorbynameAndage" resultType = "Student"> select * from student <where> <if test = " name!= null and name!= ' ' ">//如果傳過來的student對象有name屬性,並且該屬性不為空,便執行次條件 And student = #{name} </if> <if test = "age !=null and age != ' ' "> And student = #{age} </if> <if test = "age ! = null and age !=' ' And name !=null and name ! = ' ' "> And student = #{name} And student = #{age} </if> </where> </select>