MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。
雖然在以前使用動態 SQL 並非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射語句中的強大的動態 SQL 語言得以改進這種情形。
動態 SQL 元素和 JSTL 或基於類似 XML 的文本處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。MyBatis 採用功能強大的基於 OGNL 的表達式來淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
示例
1.動態SQL:if+where語句
where元素只會在至少有一個子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語句的開頭爲“AND”或“OR”,where 元素也會將它們去除。
示例,在實體類的映射文件中:
注意此處:我用的參數類型是hashMap
userMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatisstudy.dao.IUserDao">
<select id="selectUserByUsernameAndSex" parameterType="hashmap"
resultType="com.mybatisstudy.model.User">
SELECT * FROM user
<!-- where 元素只會在至少有一個子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語句的開頭爲“AND”或“OR”,where
元素也會將它們去除。 -->
<where>
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where>
</select>
</mapper>
對應的實體類接口中:
public interface IUserDao {
public List<User> selectUserByUsernameAndSex(HashMap<String,Object> argMap);
}
在單元測試類中:
兩個參數都輸入(在至少有一個子元素的條件返回 SQL 子句的情況時,會添加where)時,
此時的sql語句相當於:select * from user where name='小明' and sex='男';
只輸入後一個參數(此時因爲只有後一個參數,所以sex前面的and會被自動去掉),
此時的sql語句相當於:select * from user where sex='男';(若不用<where></where>則sql語句會變成select * from user and sex='男'; 這時便會報錯)
2.動態SQL:set和if語句
userMapper.xml
<update id="updateUserById" parameterType="com.mybatisstudy.model.User">
update user
<set>
<if test="name!=null and name!=''">
<!-- 注意後面需要有逗號 -->
name=#{name},
</if>
<if test="sex!=null and sex!=''">
<!-- 注意最後一個不需要添加逗號 -->
age=#{age}
</if>
</set>
where id=#{id}
</update>
IUserDao.java(接口)
public int updateUserById(User user);
單元測試類
@Test
public void testSetAndIf() {
User user = new User();
user.setId(1001);
user.setName("大明");
user.setSex("男");
user.setAge(21);
int line = userDao.updateUserById(user);
Assert.assertEquals(line, 1);
}
測試結果
3.動態SQL:choose(when,otherwise) 語句
示例:
userMapper.xml
<select id="selectUserByChoose" parameterType="hashmap" resultType="com.mybatisstudy.model.User">
SELECT * FROm user
<where>
<choose>
<when test="id!=null and id!=''">
id=#{id}
</when>
<when test="name!=null and name!=''">
and name=#{name}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
IUserDao.java(接口)
public List<User> selectUserByChoose(HashMap<String,Object> argMap);
單元測試類
@Test
public void testChooseAndWhen() {
HashMap<String,Object> argMap = new HashMap<String,Object>();
//argMap.put("id", 1001);
//argMap.put("name", "小明");
argMap.put("sex","男");
List<User> users = userDao.selectUserByUsernameAndSex(argMap);
for(User user : users) {
System.out.println(user);
}
}
測試結果
4.動態SQL:trim元素
trim標記是一個格式化的標記,可以完成set或者是where標記的功能
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
prefixOverrides 屬性會忽略通過管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 屬性中的內容,並且插入 prefix 屬性中指定的內容。
(1)用 trim 改寫上面的 if+where 語句
<!-- 此處我用的參數類型爲hashmap,也可以用實體類型 -->
<select id="selectUserByUsernameAndSex" parameterType="hashmap"
resultType="com.mybatisstudy.model.User">
SELECT * FROM user
<!-- where 元素只會在至少有一個子元素的條件返回 SQL 子句的情況下才去插入“WHERE”子句。而且,若語句的開頭爲“AND”或“OR”,where
元素也會將它們去除。 -->
<!-- <where>
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</where> -->
<trim prefix="where" prefixOverrides="and | or">
<if test="name!=null">
name=#{name}
</if>
<if test="sex!=null">
and sex=#{sex}
</if>
</trim>
</select>
(2)用 trim 改寫上面的 if+set 語句
<update id="updateUserById"
parameterType="com.mybatisstudy.model.User">
update user
<!-- <set>
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex!=null and sex!=''">
age=#{age}
</if>
</set> -->
<trim prefix="set" suffixOverrides=",">
<if test="name!=null and name!=''">
name=#{name},
</if>
<if test="sex!=null and sex!=''">
age=#{age}
</if>
</trim>
where id=#{id}
</update>
5.動態SQL:foreach的使用
userMapper.xml
根據所給的id集合查找user,也可以用於批量刪除等
<select id="selectUserByListId" parameterType="hashmap" resultType="com.mybatisstudy.model.User">
SELECT * FROM user
<where>
<!-- 此處要注意保持必要的空格,如此處and和C之間的空格 -->
<foreach collection="ids" item="id" open="and (" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>