MyBatis 筆記(五)——動態 SQL
在開發中,經常會遇到要執行的 SQL 語句其實並不是固定,而是隨條件的變化而變化的。對於這種情況 MyBatis 也有解決方案。
隨條件變化的 SQL
先看一個固定的 SQL 語句,查詢指定 name 和 age 的人:
<resultMap id="PersonMap" type="Person">
<id column="id" jdbcType="INTEGER" property="pid" javaType="int"/>
<result column="name" jdbcType="VARCHAR" property="pname" javaType="String"/>
<result column="age" jdbcType="INTEGER" property="page" javaType="int"/>
</resultMap>
<select id="selectWithNothing" parameterType="Person" resultMap="PersonMap">
SELECT id, name, age
FROM person
WHERE name = #{name} and age = #{age}
</select>
上面的 SQL 當 name 或 age 為空時,該查詢將會丟擲異常。
if 標籤
在不確定查詢條件是否為空時,可以用 if 標籤進行檢查:
<select id="selectWithIf" parameterType="Person" resultMap="PersonMap">
select id, name, age
from person
where 1=1
<if test="pname != null and pname != '' ">
and name = #{pname}
</if >
<if test="page != null and page != 0 ">
and age < #{page}
</if>
</select>
注意:where 後的 1 = 1 建議加上,這樣可以避免無一條件滿足時,最終的 SQL 語句中 where 後面沒有過濾條件。
呼叫方法如下:
public void selectWithIf(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Person entity = new Person();
entity.setPname("Jimmy");
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithIf", entity);
System.out.println(persons);
sqlSession.close();
}
where - if 標籤
在 SELECT 語句中,為了簡化 if 標籤,可以使用 where - if 標籤組合使用:
<select id="selectWithIfWhere" parameterType="Person" resultMap="PersonMap">
selectid, name, age
from person
<where>
<if test="pname != null and pname != '' ">
and name = #{pname}
</if>
<if test="page != null and page != 0 ">
and age < #{page}
</if>
</where>
</select>
在 where - if 標籤中,SQL 語句可以加上 and,MyBatis 會自動識別。
呼叫方法:
public void selectWithIfWhere(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
Person entity = new Person();
entity.setPname("Jimmy");
entity.setPage(30);
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithIfWhere", entity);
System.out.println(persons);
sqlSession.close();
}
set - if 標籤
在 UPDATE 語句中,為了簡化 if 標籤,可以使用 set - if 標籤組合使用:
<update id="updateWithIfSet" parameterType="Person">
updateperson
<set>
<if test="pname != null and pname != '' ">
name = #{pname}
</if>
<if test="page != null and page != 0 ">
and age = #{page}
</if>
</set>
where id = #{pid}
</update>
set 標籤為自動為每個 if 標籤中的 SQL 語句加上逗號隔開。
呼叫方法:
public void updateWithIfSet(){
SqlSession sqlSession = MyBatisUtils.getSqlSession(true);
Person entity = new Person();
entity.setPid(2);
entity.setPname("Bill");
int result = sqlSession.update("edu.wzm.mybatis.mapping.PersonMapper.updateWithIfSet", entity);
System.out.println(result);
sqlSession.close();
}
trim - if 標籤
還有一種更強大的組合標籤 trim - if,它既可以處理 SELECT語句,又可以處理 UPDATE 語句。如代替上面的 where - if 標籤:
<select id="selectWithIfTrim" parameterType="Person" resultMap="PersonMap">
SELECT id,name, age
FROM person
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="pname != null and pname != '' ">
name = #{pname}
</if>
<if test="page != null and page != 0 ">
age < #{page}
</if>
</trim>
</select>
代替上面的 set - if 標籤:
<update id="updateWithIfTrim" parameterType="Person">
UPDATE person
<trim prefix="SET" prefixOverrides=",">
<if test="pname != null and pname != '' ">
name = #{pname}
</if>
<if test="page != null and page != 0 ">
age < #{page}
</if>
</trim>
WHERE id = #{pid}
</update>
choose - when 標籤
上面的標籤都是一組條件的中的每一個條件要麼可選,要麼不選。但是對於一組互斥的條件,只能從中選擇一個,那麼上面的標籤就不好處理了,需要使用 choose - when 標籤:
<select id="selectWithChooseWhen" parameterType="Person" resultMap="PersonMap">
SELECT id, name, age
FROM person
<where>
<choose>
<when test="pname != null and pname != '' ">
name = #{pname}
</when>
<when test="page != null and page != 0 ">
AND age < #{page}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
注意:choose - when 標籤類似於 if - elseif - else。
迴圈
對於動態 SQL 非常必須的,主是要迭代一個集合,通常是用於 IN 條件。List 例項將使用 “list” 做為鍵,陣列例項以 “array” 做為鍵。
foreach 元素是非常強大的,它允許你指定一個集合,宣告集合項和索引變數,它們可以用在元素體內。它也允許你指定開放和關閉的字串,在迭代之間放置分隔符。這個元素是很智慧的,它不會偶然地附加多餘的分隔符。
注意:可以傳遞一個List例項或者陣列作為引數物件傳給是MyBatis。當你這麼做的時候,MyBatis 會自動將它包裝在一個 Map中,用名稱在作為鍵。List 例項將會以 “list” 作為鍵,而陣列例項將會以 “array” 作為鍵。
陣列
使用陣列例項作為引數:
<select id="selectWithForeachArray" resultMap="PersonMap">
SELECT id, name, age
FROM person
WHERE id IN
<foreach collection="array" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
</select>
呼叫方法:
public void selectWithForeachArray(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
int[] pids = {1, 3};
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithForeachArray", pids);
System.out.println(persons);
sqlSession.close();
}
列表
使用列表作為引數:
<select id="selectWithForeachList" resultMap="PersonMap">
SELECT id, name, age
FROM person
WHERE id IN
<foreach collection="list" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
</select>
呼叫方法:
public void selectWithForeachList(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
List<Integer> pids = new ArrayList<>();
pids.add(2);
pids.add(3);
List<Person> persons = sqlSession.selectList("edu.wzm.mybatis.mapping.PersonMapper.selectWithForeachList", pids);
System.out.println(persons);
sqlSession.close();
}