一、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”。
