myBatis/iBatis에서의 동적쿼리 - 1. foreach
Posted 2013. 7. 31. 03:28iBatis에서의 습관을 버리고 myBatis로 옮겨올 시기가 된듯합니다.
Spring3.2에서도 iBatis는 deprecated 되어 더이상 myBatis로 옮기는데 주저할수는 없는 현실이 되어버렸습니다.
오늘은 예전 iBatis에서 iterate 문으로 사용했던 부분을 forEach로 변경하는 테스트를 시험삼아 해보았습니다.
myBatis를 쓰면서 느끼는것은 이제 xml문법스타일은 버려도 되겠구나 하는 것입니다.
foreach
동적 SQL 에서 공통적으로 필요한 것은 collection 에 대해 반복처리를 하는 것이다. 종종 IN 조건을 사용하게 된다. 예를 들면,
<select id="selectPostIn" resultType="domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> </select>
foreach 요소는 매우 강력하고 collection 을 명시하는 것을 허용한다. 요소 내부에서 사용할 수 있는 item, index 두가지 변수를 선언한다. 이 요소는 또한 열고 닫는 문자열로 명시할 수 있고 반복간에 둘 수 있는 구분자도 추가할 수 있다.
참고 파라미터 객체로 MyBatis 에 List 인스턴스나 배열을 전달 할 수 있다. 그렇게 하면 MyBatis 는 Map 으로 자동으로 감싸고 이름을 키로 사용한다. List 인스턴스는 “list” 를 키로 사용하고, 배열 인스턴스는 “array” 를 키로 사용한다.
위의 내용은 myBatis 한국어 사이트 번역판에 설명되어진 것입니다만 사실 제대로된 설명이라고 하기엔, 특히나 개발감각 없는 저 같은 개발자에겐 한방에 와닿지 않습니다.
그저 따라하기 예제 샘플이 최고입니다.
User.java
public class User {
private int userIdx;
private String userName;
private Integer [] userIdxArray;
private List<Company> compList;
public ... 이하는 getter, setter 메소드이므로 생략.
}
1. 배열을 파라메터로 전달하여 foreach문을 사용하는 예
UserMapper.xml
<select id="getUserListByUserIdxArray" resultMap="User-Result" parameterType="User">
SELECT
USER_IDX as "userIdx"
, USER_NAME as "userName"
FROM USER
<trim prefix="WHERE" prefixOverrides="AND|OR">
<if test="userIdxArray != null">
AND USER_IDX IN (
<foreach collection="userIdxArray" item="a" separator=",">#{a}</foreach>
)
</if>
</trim>
</select>
WHERE 문이 오는 곳에 위치한 trim 도 iBatis에는 없던 myBatis에서 새로이 추가된 구문입니다. 보통 꼼수(?)로
위와 같이 사용하던 부분인데, 이러한 꼼수를 쓰지말라고 제공하는 구문이라고 생각합니다.
보통 if 문을 사용하는 곳 앞부분에 추가하는데, 이전 iBatis에서는 <dynamic...> 이란 구문이 아마 이에 해당했던 걸로 기억합니다.
- collection : 말 그대로 collection 객체들이 오는 곳입니다.
- item : Collection 객체들의 instance? 라고 할수 있습니다. jstl에서의 forEach를 예로 들면 "var"에 해당하는 놈이라고 할수 있겠네요. 처음엔 글자가 jstl의 items와 비슷해서 같은걸로 이해했었습니다.
- separator : 구분자.
배열이기 때문에 이 alias를 그대로 넣어주면 쿼리에 적용됩니다.
2. ArrayList를 파라메터로 전달하여 foreach문을 사용하는 예.
<if test="compList != null">
AND COMP_NAME IN (
<foreach collection="compList" item="a" separator=",">#{a.compName}</foreach>
)
</if>
...
배열 사용법과 별 차이는 없습니다.
이전 iBatis를 사용할때는 array 객체가 필요할때는 이상하게 꼭 hashmap 객체에 넣어서 보냈던 기억이 있습니다. POJO 에 넣어서 보내면 뭔가 모르게 오류가 나서 잘 안되던 기억이 있었는데(어쩌면 사용법을 틀려서 그런걸수도 있겠지만), myBatis 에 와서는 그런부분이 없습니다. 좀더 명확해졌다고 해야할까요?
오늘은 myBatis의 foreach문을 통한 반복문 사용법을 테스트 해보았습니다.
2019.01.09 추가
iBatis를 여전히 사용하는 와중에 자꾸만 헷갈리는터라 추가로 남깁니다.
iBatis의 동적쿼리 forEach중에서 제일 헷갈리면서 자주 범하는 실수입니다.
1. ParameterClass가 Object 임. Map으로 넘기는 부분과 다를까 싶지만 동일함.
2. Object 내에 ArrayList<Map<String, Object>> 를 get/set 하도록 추가.
3. 아래의 예제 쿼리는 여러개의 테이블에서 통계값을 가져와 UNION ALL 하는 쿼리이다.
BBsVO 내부 구조 및 파라메터에는 아래와 같이 데이터가 추가된다.
private String searchCategoryId;
private String searchStartDate;
private String searchEndDate;
private List<Map<String,Object>> statsParamList;
...
}
BbsVO bbsVO = new BbsVO();
bbsVO.setSearchStartDate("2018-01-01");
bbsVO.setSearchEndDate("2018-10-31");
bbsVO.setStatsParamList(bbsInfoList);
<select id="selectBbsList" parameterClass="BbsVO" resultClass="hashmap">
SELECT BBS_CNT
, ANSWER_CNT
, READ_CNT
, ATCHMNFL_CNT
, COMMUNITY_ID
FROM
<iterate property="statsParamList" open="(" close=")" conjunction="UNION ALL">
<isEqual property="statsParamList[].communityType" compareValue="BBS">
(
SELECT NVL(COUNT(a.BBS_ID),0) BBS_CNT
, NVL(SUM(a.ANSWER_COUNT),0) ANSWER_CNT
, NVL(SUM(a.READ_COUNT),0) READ_CNT
, NVL(COUNT(b.ATCHMNFL_ID),0) ATCHMNFL_CNT
, '$statsParamList[].communityId$' AS COMMUNITY_ID
FROM $statsParamList[].bbsTableNm$ a
, $statsParamList[].bbsAttchTableNm$ b
WHERE a.BBS_ID = b.BBS_ID(+)
<isNotEmpty property="searchStartDate">
<isNotEmpty property="searchEndDate">
AND a.REG_DT BETWEEN REPLACE(#searchStartDate#, '-', '')
AND REPLACE(#searchEndDate#,'-','') ||'235959'
</isNotEmpty>
</isNotEmpty>
)
</isEqual>
</iterate>
</select>
추가로 참고할 블로그 소개 : http://fogs0.blogspot.com/2012/04/ibatis-iterate-in-isequal.html
끝.
'개발노트 > iBatis/myBatis' 카테고리의 다른 글
myBatis 1:N 의 결과를 select 하기 (1) | 2013.12.09 |
---|---|
[myBatis오류]Improper inline parameter map format (1) | 2013.08.25 |
iBatis에서 myBatis로 변경시 selectKey에 대한 변경사항 (2) | 2013.05.04 |
iBatis에서 테이블명 변경등의 쿼리를 이용할때 주의할점 (0) | 2010.09.08 |
iBatis에서 selectKey사용시 주의할 점. (0) | 2010.06.18 |
- Filed under : 개발노트/iBatis/myBatis