Mybatis框架的使用之五(動態SQL)
假定一張使用者表,要通過姓名(userName)模糊以及職位id(userRole)篩選顯示所有符合條件的資訊。普通sql語句的寫法是:
select * from user
where userName CONCAT('%',#{userName},'%')
and userRole ={userRole}
有這樣一種情況,在使用者進行多條件查詢資料或更新資料的時候,可能會不進行一項或多項引數的傳值,比如userName不進行傳參,那麼執行的時候上述語句實際執行的是
select * from user where userName CONCAT(’%’,null
模糊查詢名字中有null,職位id是xx的人,這樣很顯然查不出資料,達不到預期的設想。
解決方案:if+trim標籤
上述語句可以優化為:
//省略程式碼
select * from user
<trim prefix="where" prefixOverrides="and">
<if test="userName!=null and userName !=''">
AND userName like CONCAT('%',#{userName} ,'%')
</if>
<if test="userRole!=null">
AND userRole = #{userRole}
</if>
</trim>
//省略程式碼
這條語句的意思就是:如果userName不為null且不為空字串,就執行這一部分語句,並在語句之前增加 ‘where’ 關鍵字,否則跳過。如果userRole不為null,就進行這一部分語句,並在語句之前增加 ‘where’ 關鍵字(如果之前的語句已經增加過了就不會再增加)。如果有上述內容中有多餘的’and’關鍵字,就把它刪除。
首先< if>< /if>標籤的作用與在Java中一樣,是進行一個判斷,"test"屬性就是要判斷的條件,如果返回值為真,則進行標籤內語句,否則跳過。
< trim>< /trim>標籤則是對多餘的sql語句進行動態的修改,prefix表示開頭的資訊,如果後面的if條件有返回值就會在開頭加上,prefixOverrides表示結尾指定內容的忽略 suffix表示最後的固定結尾內容,在這條語句中沒有使用到。
通過這樣的修改,假設當傳入的userName是null或者’’,userRole是1的時候,語句會動態的修改成
select * from user
where userRole =1
或者當傳入的userName是"趙"而userRole是null的時候,語句會動態的修改成:
select * from user
where userRole =1
where userName like CONCAT(’%’,‘趙’,’%’)
又或者,當userName和userRole都是null,那麼語句會動態的修改成:
select * from user
總的來說< trim>標籤很強大,除了select ,update set也可以使用,就不贅述了。
< foreach>標籤
需求:指定使用者職位userRole(1-n個),獲取這些使用者角色下的使用者列表資訊
舉例:select * from user where userRole in (2,3)
//省略程式碼
select * from user where userRole in
<foreach collection="array"
item="roleIds" open="(" separator="," close=")">
#{roleIds}
</foreach>
//省略程式碼
屬性:
item:集合裡每一個元素進行迭代時的別名
index:指定一個名稱,代表每次迭代到的位置
collection:必須指定 。list、array、map-key
open:表示語句以什麼來開始
separator:迭代之間以什麼符號進行間隔
close:語句以什麼結束
上述mapper方法對應的介面方法是
List<User> getUserByRoleId_foreach_array(Integer[] roleIds);
測試方法:
public void getUserByRoleId_foreach_array() {
SqlSession sqlSession = null;
List<User> userList = new ArrayList<>();
Integer[] roleIds = {1, 2};
try {
sqlSession = MyBatisUtils.getSQLSession();
userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleIds);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
for (User user : userList) {
logger.debug("user ===========> id: " + user.getId() +
", userName: " + user.getUserName() +
", userAddress: " + user.getAddress() +
", userRole: " + user.getUserRole());
}
}
上述程式碼中指定了迭代的型別(collection)是陣列array,實際上迭代集合list也是基本一致的用法。
collection:map-key 這裡迭代的是一個map,具體到map的key。
需求:指定使用者職位userRole(1-n個),且性別(gender)是1的使用者,獲取這些使用者列表資訊
從需求可以看出實際上有兩個限制條件,條件1是固定值,條件2是個集合。這樣就可以考慮用map的方式進行迭代查詢。
介面方法:
List<User> getUserByRoleId_foreach_map(Map<String,Object> roleMap);
mapper檔案:
//省略程式碼
select * from user where gender=#{gender}
AND userRole IN
<foreach collection="userRole" item="roleMap"
open="(" separator="," close=")">
#{roleMap}
</foreach>
//省略程式碼
測試方法:
public void getUserByRoleId_foreach_map() {
SqlSession sqlSession = null;
Map<String,Object> roleMap = new HashMap<>();
List<Integer> roleList = new ArrayList<>();
roleList.add(2);
roleList.add(3);
roleMap.put("gender",1);
roleMap.put("userRole",roleList);
List<User> userList = new ArrayList<>();
try {
sqlSession = MyBatisUtils.getSQLSession();
userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_map(roleMap);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
logger.debug("getUserListByRoleIdTest userList.size : " + userList.size());
for (User user : userList) {
logger.debug("user ===========> id: " + user.getId() +
", userName: " + user.getUserName() +
", userAddress: " + user.getAddress() +
", userRole: " + user.getUserRole()+
", gender: " + user.getGender()
);
}
}
這裡值得注意的就是用於存放userRole引數的list集合的key名要跟mapper對映檔案裡的collection的值保持一致。用於存放所有引數的map集合的key要跟mapper對映檔案裡的item的值以及#{引數名}保持一致。
到這裡,Mybatis的使用系列就告一段落,該吃午飯了。