Mybatis動態SQL之使用foreach完成復雜查詢


一、foreach概述

對於一些SQL語句中含有in條件、需要迭代條件集合來生產的情況,就需要使用foreach標簽來實現SQL條件的迭代。foreach主要用在構建in條件中,它可以在SQL語句中迭代一個集合。它的屬性主要有item、index、collection、separator、close、open

二、foreach迭代數組類型的入參

需求:根據用戶角色列表來獲取用戶信息列表

public List<User> getUserByRoleId_foreach_array(Integer[] roleIds);
<select id="getUserByRoleId_foreach_array" resultMap="userMapByRole">
  select * from smbms_user where userRole in <foreach collection="array" item="roleIds" open="(" separator="," close=")"> #{roleIds} </foreach>
</select>

<resultMap id="userMapByRole" type="User">
  <id property="id" column="id"/>
  <result property="userCode" column="userCode"/>
  <result property="userName" column="userName"/>
</resultMap> 
@Test
public void testGetUserByRoleId_foreach_array(){
    SqlSession sqlSession = null;
    List<User> userList = new ArrayList<>();
    Integer[] roleIds = {2, 3};
    try {
        sqlSession = MyBatisUtil.createSqlSession();
        userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleIds);
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        MyBatisUtil.closeSqlSession(sqlSession);
    }
    logger.debug("userList.size-->" + userList.size());
    for (User user:userList){
        logger.debug("user=====>id:" + user.getId() 
                + ", userCode:" + user.getUserCode()
                + ", userName:" + user.getUserName()
                + ", userRole:" + user.getUserRole());
    }
}

 foreach標簽的基本屬性具體信息如下

  • item:表示集合中每一個元素進行迭代時的別名
  • index:指定一個名稱,用於表示在迭代過程中,每次迭代到的位置
  • open:表示該語句以什么開始,in條件語句是以“(”開始 
  • separator:表示在每次迭代之間以什么符號作為分隔符,in條件語句以“,”作為分隔符
  • close:表示該語句以什么結束,in條件語句是以“)”結束
  • collection:該屬性必需指定,不同情況下,該屬性的值是不一樣的
    • 若入參為單參數且參數類型是一個List,collection屬性值為list
    • 若入參為單參數且參數類型是一個數組,collection屬性值為array(此處傳入參數Integer[] roleIds為數組類型,故此處collection屬性值設為“array”)
    • 若傳入參數為多參數,就需要把它們封裝為一個Map進行處理

配置文件中的parameterType是可以不配置的,MyBatis會自動把它封裝成一個Map傳入。

三、foreach迭代List類型的入參

public List<User> getUserByRoleId_foreach_array(List<Integer> roleList);
<select id="getUserByRoleId_foreach_array" resultMap="userMapByRole">
  select * from smbms_user where userRole in
  <foreach collection="list" item="roleList" open="(" separator="," close=")"> #{roleList} </foreach>
</select>

<resultMap id="userMapByRole" type="User">
  <id property="id" column="id"/>
  <result property="userCode" column="userCode"/>
  <result property="userName" column="userName"/>
</resultMap> 

測試關鍵代碼如下

List<User> userList = new ArrayList<>();
List<Integer> roleList = new ArrayList<>();
roleList.add(2);
roleList.add(3);
try {
    sqlSession = MyBatisUtil.createSqlSession();
    userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleList);
}

foreach允許我們指定一個集合,指定開始和結束的字符,也可加入一個分隔符到迭代器中,並能夠智能處理該分隔符,不會出現多余的分隔符

四、foreach迭代Map類型的入參

MyBatis入參若為多個參數,除了使用@Param注解,還可以把它們封裝為一個Map進行處理

public List<User> getUserByRoleId_foreach_array(Map<String, Object> conditionMap);
<select id="getUserByRoleId_foreach_array" resultMap="userMapByRole">
  select * from smbms_user where gender=#{gender} and userRole in
  <foreach collection="roleIds" item="roleMap" open="(" separator="," close=")">
    #{roleMap}
  </foreach>
</select>

<resultMap id="userMapByRole" type="User">
  <id property="id" column="id"/>
  <result property="userCode" column="userCode"/>
  <result property="userName" column="userName"/>
</resultMap> 

測試方法中,把用戶列表和性別兩個參數封裝成一個Map進行方法入參

List<User> userList = new ArrayList<>();
List<Integer> roleList = new ArrayList<>();
roleList.add(2);
roleList.add(3);
Map<String, Object> conditionMap = new HashMap<>(); conditionMap.put("gender", 1); conditionMap.put("roleIds", roleList); try {
    sqlSession = MyBatisUtil.createSqlSession();
    userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(conditionMap);
}

由於入參為Map,那么在SQL語句中需根據key分別獲得相應的value值,比如SQL語句中的#{gender}獲取的是Map中key為“gender”的性別條件,而collection="roleIds"獲取的是Map中key為“roleIds”的角色id的集合。

單參數也可以封裝為Map進行入參。MyBatis在進行參數入參的時候,都會把它封裝成一個Map,而Map的key就是參數名,對應的參數值就是Map的value。若參數為集合的時候,Map的key會根據傳入的是List還是數組對象相應的指定為“list”或者“array”。這樣的好處是,我們可以自由指定Map的key,如下

public List<User> getUserByRoleId_foreach_array(Map<String, Object> roleMap);
<select id="getUserByRoleId_foreach_array" resultMap="userMapByRole">
  select * from smbms_user where userRole in
  <foreach collection="rKey" item="roleMap" open="(" separator="," close=")">
    #{roleMap}
  </foreach>
</select>

<resultMap id="userMapByRole" type="User">
  <id property="id" column="id"/>
  <result property="userCode" column="userCode"/>
  <result property="userName" column="userName"/>
</resultMap>
List<User> userList = new ArrayList<>();
List<Integer> roleList = new ArrayList<>();
roleList.add(2);
roleList.add(3);
Map<String, Object> roleMap = new HashMap<>(); roleMap.put("rKey", roleList); try {
    sqlSession = MyBatisUtil.createSqlSession();
    userList = sqlSession.getMapper(UserMapper.class).getUserByRoleId_foreach_array(roleMap);
}

五、choose(when、otherwise)

對於某些查詢需求,雖有多個查詢條件,但不想應用所有的條件,只想選擇其中一種情況下的查詢結果。和Java中switch語句類似,MyBatis提供了choose元素來滿足這種需求

需求:根據條件(用戶名稱、用戶角色、用戶編碼)中的任意一個即可,若前三個條件都沒提供,默認提供最后一個條件(創建時間,在指定的年份內)來完成查詢操作 

public List<User> getUserList_choose(@Param("userName") String userName,
                                     @Param("userRole") Integer roleId,
                                     @Param("userCode") String userCode,
                                     @Param("creationDate") Date creationData);
<select id="getUserList_choose" resultType="User">
  select * from smbms_user where 1=1 <choose>
    <when test="userName!=null and userName!=''">
      and userName like connect('%', #{userName}, '%')
    </when>
    <when test="userCode!=null and userCode!=''">
      and userCode like connect('%', #{userCode}, '%')
    </when>
    <when test="userRole!=null">
      and userRole = #{userRole}
    </when>
    <otherwise>
      and YEAR(creationDate) = YEAR(#{creationDate})
    </otherwise>
  </choose>
</select>
String userName="";
Integer roleId=null;
String userCode="";
Date creationDate = new SimpleDateFormat("yyyy-MM-dd").parse("2019-01-01");
userList = sqlSession.getMapper(UserMapper.class).getUserList_choose(userName, roleId, userCode, creationDate);

choose一般與when、otherwise配套使用。

when元素:當其test屬性中條件滿足的時候,就會輸出when元素中的內容。跟Java中switch效果差不多,同樣按照條件的順序來進行處理,當when中一旦有條件滿足,就會跳出choose,即所有的when和otherwise條件中,只有一個條件會輸出。

otherwise元素:當when中的所有條件都不滿足的時候,就會自動輸出otherwise元素中的內容

SQL語句后面加入“where 1=1”的原因是我們不需要再去處理多余的“and”。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM