1. 程式人生 > >Mybatis框架的使用之五(動態SQL)

Mybatis框架的使用之五(動態SQL)

在這裡插入圖片描述

假定一張使用者表,要通過姓名(userName)模糊以及職位id(userRole)篩選顯示所有符合條件的資訊。普通sql語句的寫法是:

select * from user 
where userName CONCAT('%',#{userName},'%') 
and userRole ={userRole}

有這樣一種情況,在使用者進行多條件查詢資料或更新資料的時候,可能會不進行一項或多項引數的傳值,比如userName不進行傳參,那麼執行的時候上述語句實際執行的是
select * from user where userName CONCAT(’%’,null

,’%’) and userRole ={userRole}
模糊查詢名字中有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的使用系列就告一段落,該吃午飯了。