이전에 살펴본 DynamicQuery부분에 사용한 옵션 외에 다양한 옵션이 제공 된다. 일반적으로 이런 옵션들을 이용할때 DAO에 쿼리가 박혀있을 경우 매우 복잡해진다. 따라서 스토어드 프로시저를 이용한다거나 하는 방식을 택하게 되는데, iBATIS에서 지원하는 옵션들을 살펴보자
- <!--property가 존재 하는지 검사(map의경우 property를 key로 검색실패) -->
- <isPropertyAvailable property=""></isPropertyAvailable>
- <!--property가 존재 하지 않는지 검사(map의경우 property를 key로 검색실패) -->
- <isNotPropertyAvailable property=""></isNotPropertyAvailable>
- <!--property가 null인지 검사 -->
- <isNotNull property=""></isNotNull>
- <!--property가 null이 아닌지 검사 -->
- <isNull property=""></isNull>
- <!-- property가 비어있는지 검사("".equals) 검사-->
- <isEmpty prepend=""></isEmpty>
- <!-- property가 비어있지 않은지 검사(!"".equals) 검사-->
- <isNotEmpty prepend=""></isNotEmpty>
- <!-- property가 비교값과 같은지 검사-->
- <isEqual property="" compareValue="" compareProperty=""></isEqual>
- <!-- property가 비교값과 같지 않은지 검사-->
- <isNotEqual property="" compareValue="" compareProperty=""></isNotEqual>
- <!-- property가 비교값보다 큰지 검사 -->
- <isGreaterThan property="" [compareValue="" || compareProperty=""]></isGreaterThan>
- <!-- property가 비교값보다 큰거나 같은지 검사 -->
- <isGreaterEqual property="" [compareValue="" || compareProperty=""]></isGreaterEqual>
- <!-- propety가 작은지 검사 -->
- <isLessThan property="" [compareValue="" || compareProperty=""]></isLessThan>
- <!-- propety가 작거나 같은지 검사 -->
- <isLessEqual property="" [compareValue="" || compareProperty=""]></isLessEqual>
- <!-- property를 반복하며 추가. 반복시 값의 사이에 conjunction정의 문자 삽입 -->
- <iterate property="" open="(" close=")" conjunction=","></iterate>
그냥 눈으로만 봐도 충분히 숙지할 수 있는 사항이므로 별도의 설명은 하지 않겠다. 조건에 property는 당연히 들어가는것이 원칙이다. 비교할 대상이나 검사할 대상이 없다면 뭐하러 이런 조건을 사용 하겠는가? 어렵지 않은 내용이지만 한가지 숙지해야 할 사항이 있다.
바로 이항연산자 부분에서 compareValue와 compareProperty인데 다른 부분은 property를 이용해 비교했다. 같은 property가 들어가는걸로 보아 compareProperty는 프로퍼티 중에서 비교하는 것을알수 있다.즉 '같이 넘어온 객체의 프로퍼티와 비교'하여 구문을 추가할지 선택하는것이다.
compareValue는 정적인 값이다. 예를들어 조건이 '성적이 100점 이하'일 경우 100은 정적인 값이다. 만약 이것을 compareProperty로 이용한다면 사용할때마다 '100'의 값을 셋팅해야할 것이다. 이럴때 compareValue를 이용하면 프로그램 코드에 별도로 관리할 필요가 없으므로 유용하게 사용할수 있다. 그럼 예제를 살펴보자.
boardManager.xml
- <typeAlias alias="boardbean" type="pupustory.ibatis.beans.BoardBean"/>
- <resultMap class="boardbean" id="boardbean">
- <result property="postId" column="post_Id"/>
- <result property="postTitle" column="post_Title"/>
- <result property="postWriter" column="post_Writer"/>
- <result property="postBody" column="post_Body"/>
- </resultMap>
- <parameterMap class="boardbean" id="boardbean">
- <parameter property="postId" />
- <parameter property="postTitle"/>
- <parameter property="postWriter"/>
- <parameter property="postBody"/>
- </parameterMap>
- <select id="select.board" resultMap="boardbean"
- parameterClass="boardbean" >
- SELECT
- A.POST_ID AS POST_ID
- ,A.POST_TITLE AS POST_TITLE
- ,A.POST_WRITER AS POST_WRITER
- ,B.POST_BODY AS POST_BODY
- FROM TB_MAIN_BOARD A, TB_SUB_BOARD B
- WHERE A.POST_ID = B.POST_ID
- <dynamic open="" close="">
- <isNull prepend=" AND " property="postId">
- 11=1
- </isNull>
- <isNotNull prepend=" AND " property="postId">
- a.post_id = #postId#
- </isNotNull>
- <isNotNull prepend=" AND " property="postTitle">
- post_title like '%' || #postTitle# || '%'
- </isNotNull>
- <isNotNull prepend=" AND " property="postWriter">
- post_Writer like '%' || #postWriter# || '%'
- </isNotNull>
- <isNotNull prepend=" AND " property="postBody">
- post_body like '%' || #postBody# || '%'
- </isNotNull>
- </dynamic>
- </select>
- <insert id="insert.main.board" parameterClass="boardbean">
- insert into tb_main_board
- values(#postId#,#postTitle#,#postWriter#)
- </insert>
- <insert id="insert.sub.board" parameterClass="boardbean">
- insert into tb_sub_board(post_id, post_body)
- values(#postId#,#postBody#)
- </insert>
- </sqlMap>
BoardBean.java
- package pupustory.ibatis.beans;
- public class BoardBean {
- String postId;
- String postTitle;
- String postWriter;
- String postBody;
- public String getPostBody() {
- return postBody;
- }
- public void setPostBody(String postBody) {
- this.postBody = postBody;
- }
- public String getPostId() {
- return postId;
- }
- public void setPostId(String postId) {
- this.postId = postId;
- }
- public String getPostTitle() {
- return postTitle;
- }
- public void setPostTitle(String postTItle) {
- this.postTitle = postTItle;
- }
- public String getPostWriter() {
- return postWriter;
- }
- public void setPostWriter(String postWriter) {
- this.postWriter = postWriter;
- }
- public String toString() {
- return "postId["+postId+"]"
- +"postTitle["+postTitle+"]"
- +"postWriter["+postWriter+"]"
- +"postBody["+postBody+"]";
- }
- }
BoardBiz.java
- package pupustory.ibatis.board;
- import pupustory.ibatis.manager.DBManager;
- import pupustory.ibatis.beans.BoardBean;
- import java.sql.SQLException;
- public class BoardBiz {
- DBManager manager = DBManager.getInstance();
- // 가상 데이터 삽입
- public void insertVirData() throws SQLException{
- BoardBean bean = null;
- final int MAX_BOARD_DATA = 10;
- manager.startTransaction();
- manager.startBatch();
- for (int i=0;i<MAX_BOARD_DATA;i++) {
- bean = new BoardBean();
- bean.setPostId(i+"");
- bean.setPostTitle("제목! "+i);
- bean.setPostWriter("pupustory"+i);
- bean.setPostBody("본문 히히히히 헤헤"+i);
- manager.getMapper().insert("insert.main.board", bean);
- manager.getMapper().insert("insert.sub.board", bean);
- }
- manager.executeBatch();
- manager.commitTransaction();
- }
- // 게시물 조회
- public java.util.List getPost(BoardBean bean)
- throws SQLException {
- return
- (java.util.List)manager.getMapper().queryForList("select.board",bean);
- }
- }
StartApp.java
- package pupustory.ibatis.board;
- import java.sql.SQLException;
- import pupustory.ibatis.beans.BoardBean;
- public class StartApp {
- public static void main(String ar[]) throws SQLException{
- BoardBiz biz = new BoardBiz();
- //biz.insertVirData();
- BoardBean bean = null;
- java.util.List list = biz.getPost(bean);
- for (int i=0;i<list.size();i++) {
- System.out.println(list.get(i).toString());
- }
- bean = new BoardBean();
- // id 3번 게시물 조회
- bean.setPostId("3");
- list = biz.getPost(bean);
- for (int i=0;i<list.size();i++) {
- System.out.println(list.get(i).toString());
- }
- // 본문에 '4'문자 포함한 게시물 조회
- bean = new BoardBean();
- //bean.setPostId("2");
- bean.setPostBody("4");
- list = biz.getPost(bean);
- for (int i=0;i<list.size();i++) {
- System.out.println(list.get(i).toString());
- }
- }
- }
조회조건에 들어올 값을 확인하고, null이 아닐경우 검색해서 출력한다. equal같은 검색조건을 추가하려 했지만.. 귀찮기도해서 --; 어차피 사용법은 동일하다. 그리고 dynamic부분의 prepend는 삭제했다. 이유는 이미 join을 하기위해 where를 호출했고, 뒤에 올 조건이 있을지 없을지 미지수다. 따라서 삭제 했다. 1=1은 게시 전에 몇가지 만지작 거리다 남은 코드이므로 무시해도 무관하다.
단항,이항 검색조건은 위와 같이 수행하면 되므로 어려울 것이 없다. 그렇다면 이번엔 이터레이터에 대해 알아볼 것이다. 이전에 설명 했지만 만약 사용자가 ' where board_id in (....) '와 같이 몇건이 들어올지 모르는 경우에 유용 하다.
이부분은 $$를 이용한 statment를 이용할 수도 있겠지만 이건 매우 위험하다. sql injection때문에 그렇다. 어플에서 .replace했다면 상관 없겠지만 그래도 프레임워크를 이용하니 .. 기능을 이용해 보도록 하자.
먼저 IN ( ...) 부분엔 정확히 얼마의 문자가 올지 모른다. 한가지 유추할 수 있는 것은 여기엔 배열이 적합한 것 이다. 새로운 예를 만드는 것 보다 위의 코드를 조금 변경해 작성하도록 하자. 먼저 빈즈에 POST_ID값이 저장될 배열 변수를 하나 추가한다.
- private String rePostId;
- public String getRePostId() {
- return rePostId;
- }
- public void setRePostId(String rePostId) {
- this.rePostId = rePostId;
- }
- public String toString() {//toString()는 값 확인을 위해 변경 함
- return "postId [" +rePostId+"]"
- +" postTitle [" +postTitle+"]"
- +" postWriter [" +postWriter+"]"
- +" postBody [" +postBody+"]"
- +" parentPostId [" +parentPostId+"]";
- }
이제 중요한 sqlmap부분이다.
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE sqlMap
- PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
- "http://ibatis.apache.org/dtd/sql-map-2.dtd">
- <sqlMap namespace="UserManager">
- <typeAlias alias="postreply" type="pupustory.ibatis.beans.PostReplyBean"/>
- <resultMap class="postreply" id="postreply.result" >
- <result property="rePostId" column="POST_ID" />
- <result property="postTitle" column="POST_TITLE" />
- <result property="postWriter" column="POST_WRITER" />
- <result property="postBody" column="POST_BODY" />
- <result property="parentPostId" column="PARENT_POST_ID" />
- </resultMap>
- <parameterMap class="postreply" id="postreply.param">
- <parameter property="postId" />
- <parameter property="postTitle"/>
- <parameter property="postWriter"/>
- <parameter property="postBody" />
- <parameter property="parentPostId"/>
- </parameterMap>
- <select id="select.dynamic.query" resultMap="postreply.result"
- parameterClass="postreply" >
- SELECT * FROM TB_QNA_BOARD
- <dynamic prepend="WHERE">
- <iterate property="postId"
- conjunction="," open="post_id IN (" close=")" >
- #postId[]#
- </iterate>
- </dynamic>
- </select>
- </sqlMap>
반복 부분을 iterator를 사용했다. 실행코드를 살펴보자.
- package pupustory.ibatis.dynamicquery;
- import pupustory.ibatis.beans.PostReplyBean;
- public class StartApp {
- public static void main(String ar[]) throws java.sql.SQLException {
- PostReplyBean bean = new PostReplyBean();
- DynamicQueryBiz biz = new DynamicQueryBiz();
- String[] postIds = {"1","2","4","5","7","9"};
- bean.setPostId(postIds);
- java.util.List list = biz.getPostBoard(bean);
- if (list.get(0) instanceof PostReplyBean) {
- System.out.println("true");
- }
- for (int i=0;i<list.size();i++) {
- bean = (PostReplyBean)list.get(i);
- System.out.println(bean.toString());
- }
- }
- }
어려운 구문은 없다. xml에서 open부분에 in ( 를 추가 했고, 배열마다 구분문자는 ','로 지정했다. 완료 후 ) 로 닫으니
와 같은 sql 구문이 생성 된다. resultMap에선 실제 우리가 가져와야 할 빈의 변수와 맵핑하면 된다.