이클립스를 실행합니다.

퍼스펙티브는 Java 를 기준으로 설명합니다.

 

새로운 자바 프로젝트를 만듭니다.

프로젝트 이름은 MyBatis로 하겠습니다.

 

퍼스펙티브는 Java 로 하고 새로운 프로젝트를 만들면 프로젝트 이름의 폴더 아래 서브 폴더 bin 폴더와 src 폴더가 만들어지게 되죠.

MyBatis 실습을 위해서 저는 lib 폴더를 하나 더 만들겠습니다.

lib 롤더에는 MyBatis와 MySQL용 JDBC 드라이버 파일을 복사해 넣습니다.

 

MyBatis는 http://www.mybatis.org/ 에서 Java 메뉴에서 찾습니다.

MySQL용 JDBC 드라이버는 http://www.mysql.com/ 에서 찾을 수 있습니다.

 

이클립스에서 Package뷰에서 MyBatis 프로젝트에 마우스로 활성화 한 후,

마우스 오른쪽 키를 이용해서 컨텍스트 메뉴를 보이게 한 후 Build Path , Configure Build Path 를 차례로 선택합니다.

이어 나온 다이얼로그 박스에서 Libraries 탭을 선택하고 Add External JARs를 클릭하여 MyBatis팩키지와 MySQL JDBC 드라이버 팩키지를 추가합니다.

 

다음으로

src폴더에서 db.properties 와 Configuration.xml 를 아래와 같이 작성합니다.

 

db.properties 파일 내용

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/javaschool

username=javaschool

password=1234

 

Configuration.xml 파일 내용

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<properties resource="db.properties" />

<environments default="development">

<environment id="development">

<transactionManager type="JDBC" />

<dataSource type="POOLED">

<property name="driver" value="${driver}" />

<property name="url" value="${url}" />

<property name="username" value="${username}" />

<property name="password" value="${password}" />

</dataSource>

</environment>

</environments>

<mappers>

<mapper resource="User.xml" />

</mappers>

</configuration>

 

다음으로 User.java를 아래와 같이 작성합니다.

 

package net.java_school.mybatis.example;

public class User {

private String email;

private String name;

private String passwd;

 

public String getEmail() {

return email;

}

 

public void setEmail(String email) {

this.email = email;

}

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public String getPasswd() {

return passwd;

}

 

public void setPasswd(String passwd) {

this.passwd = passwd;

}

 

public String toString() {

String result = null;

result = String.format("[User:Email=%s,Password=%s,Name=%s]", email,passwd,name);

return result;

}

}

 

다음으로 src폴더에서 User.xml 파일을 아래와 같이 작성합니다.

 

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="User">

<!-- 리절트 맵 정의 -->

<resultMap id="UserResult" type="net.java_school.mybatis.example.User">

<result property="email" column="email" />

<result property="name" column="name" />

<result property="passwd" column="passwd" />

</resultMap>

 

<!-- select 쿼리문 정의 -->

<select id="selectAllUsers" resultMap="UserResult">

select * from user

</select>

 

</mapper>

 

마지막으로 main메소드가 있는 UserTest.java 파일을 아래와 같이 작성합니다.

 

package net.java_school.mybatis.example;

 

import java.io.*;

import org.apache.ibatis.io.*;

import org.apache.ibatis.session.*;

import java.util.*;

 

public class UserTest {

@SuppressWarnings("unchecked")

public static void main(String[] args) {

String resource = "Configuration.xml";

Reader reader;

 

try {

reader = Resources.getResourceAsReader(resource);

SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

SqlSession session = sqlMapper.openSession();

try {

List<User> list = (List<User>)session.selectList("selectAllUsers");

for(User user : list) {

System.out.println(user);

}

} finally {

session.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

이클립스에서 실행합니다.

명령프롬프트에서 실행할 때는 bin 디렉토리로 이동 후 아래와 같이 classpath 옵션을 적절히 추가해 주어야 합니다.

 

kim@kim-android:~/java/MyBatis/bin$ java -classpath /home/kim/java/MyBatis/lib/mybatis-3.0.5.jar:/home/kim/java/MyBatis/lib/mysql-connector-java-5.1.17-bin.jar:. net.java_school.mybatis.example.UserTest

참고문서

스트럿츠2 프로그래밍 입문 -대림출판사,성윤정,이명숙 저 - Chapter13

 

출처 - http://cafe.naver.com/webprogramguide.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=438&


===================================================================================


mybatis 3.0 에서 resultMap 활용 ◈ Framework/mybatis 3.x2011/12/01 20:37

1. 하나의 테이블에 대한 결과 조회

 

         <resultMap id="bbsDataResult" type="kr.xboard.dao.bbsdata.BbsDataBean">

                  <id property="bbsId" column="S_BBS_ID" javaType="java.lang.String"/>

                  <id property="bbsIdx" column="I_BBS_IDX" javaType="int"/>

                  <result property="parentIdx" column="I_PARENT_IDX" javaType="int"/>

                  <result property="idxLeft" column="I_IDX_LEFT" javaType="int"/>

                  <result property="idxRight" column="I_IDX_RIGHT" javaType="int"/>

                  <result property="bbsTitle" column="S_BBS_TITLE" javaType="java.lang.String"/>

                  <result property="bbsDesc" column="S_BBS_DESC" javaType="java.lang.String"/>

         </resultMap>

 

         <select id="getBbsDataList" parameterType="BbsDataBean" resultMap="bbsDataResult">

         <!-- bbs_data 의 목록 -->

                  SELECT S_BBS_ID,

                              I_BBS_IDX,

                              I_PARENT_IDX,

                              I_IDX_LEFT,

                              I_IDX_RIGHT,

                              S_BBS_TITLE,

                              S_BBS_DESC

                    FROM bbs_data

                  <where>

                           <if test="bbsId != null and bbsId != ''">

                                   AND S_BBS_ID = #{bbsId}

                           </if>

                           <if test="bbsIdx != null and bbsIdx != ''">

                                   AND I_BBS_IDX = #{bbsIdx}

                           </if>

                  </where>

         </select>

 

getBbsDataList 쿼리에서 결과가 bbsDataResult 로 맵핑이 된다.

resultmap  id 는 pk 여부를 나타내며이후 설명할 association, collection 에서 중요하게 사용된다.

 

게시판 내용을 보기를 하기 위해서는

게시판에 대한 기본 정보 (bbs_info) 와 게시글 (bbs_data), 게시글에 첨부 파일(bbs_file), 게시글에 대한 덧글 (bbs_comment)가 있을 수 있다.

이와 같이 4개의 테이블에 대해 각각 쿼리를 작성하지 않고,

하나의 resultmap 에서 처리 가능하도록 해보자

 

 

Entity Generator 로 생성된 BbsDataBean 파일에 다음과 같이

게시판 정보 (BbsInfoBean), 첨부파일 (BbsFileBean), 덧글 (BbsCommentBean) 을 각각 등록한다.

BbsInfoBean 은 게시글에 대해 1개의 row 를 가지고

BbsFileBean 과 BbsCommentBean  n개의 row 를 가질 수 있다.

 

kr.xboard.dao.bbsdata.BbsDataBean.java

 

public class BbsDataBean {

        

 

         /**

          * 게시판 정보

          */

         public BbsInfoBean bbsInfoBean;

        

         /**

          * 게시물 파일 목록

          */

         public List<BbsFileBean> bbsFileBeans;

        

         /**

          * 게시물 덧글 목록

          */

         public List<BbsCommentBean> bbsCommentBeans;

        

 

    /**

     * bbs_data.S_BBS_ID

     * defaultValue = ''

     *

     * 게시판 코드

     */

    private String bbsId = "";

 

sqlmap.xml 파일에 수정된 BbsDataBean 파일에 대응하는 resultMap 을 생성한다.

 

kr.xboard.dao.bbsdata.BbsData-sqlmap.xml

 

         <resultMap id="bbsDataExResult" extends="bbsDataResult" type="BbsDataBean">

                  <association property="bbsInfoBean" column="{bbsId=S_BBS_ID}"select="kr.xboard.dao.bbsinfo.BbsInfoDao.getBbsInfoItem"/>

                  <collection property="bbsFileBeans" ofType="BbsFileBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}" select="kr.xboard.dao.bbsfile.BbsFileDao.getBbsFileList"/>

                  <collection property="bbsCommentBeans" ofType="BbsCommentBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}"select="kr.xboard.dao.bbscomment.BbsCommentDao.getBbsCommentList"/>

         </resultMap>     

 

select="kr.xboard.dao.bbsinfo.BbsInfoDao.getBbsInfoItem"

 getBbsInfoItem 은 kr.xboard.dao.bbsInfo.BbsInfo-sqlmap.xml 파일에 존재한다.

column="{bbsId=S_BBS_ID}"

의 bbsId  pk 값을 나타내며, getBbsInfoItem select query  resultMap 

 

         <resultMap id="bbsInfoResult" type="kr.xboard.dao.bbsinfo.BbsInfoBean">

                  <id property="bbsId" column="S_BBS_ID" javaType="java.lang.String"/>

 

에서 id 로 등록되어 있다.

column 의 값에 따라 select 에서 수행되는 쿼리의 #{bbsId} 값이 맵핑이 된다.

 

이제 getBbsDataItem  resultMap 을 새로 추가한 bbsDataExResult 로 변경한 후

 

         <select id="getBbsDataItem" parameterType="BbsDataBean" resultMap="bbsDataExResult">

         <!-- bbs_data 의 상세 내역 -->

                  SELECT S_BBS_ID,

                              I_BBS_IDX,

                              I_PARENT_IDX,

                              I_IDX_LEFT,

                              I_IDX_RIGHT,

                              S_BBS_TITLE,

                              S_BBS_DESC

                    FROM bbs_data

                  <where>

                           <if test="bbsId != null and bbsId != ''">

                                   AND S_BBS_ID = #{bbsId}

                           </if>

                           <if test="bbsIdx != null and bbsIdx != ''">

                                   AND I_BBS_IDX = #{bbsIdx}

                           </if>

                  </where>

         </select>

 

테이블에 몇개의 데이터를 추가하자.

그리고 test.xboard.BbsDataControllerTest.java 파일을 열어

 

@Test

    public void getBbsDataItemTest () {

                  BbsDataBean bean = new BbsDataBean();

                  bean.setBbsId("1");                // 테스트용

                  bean.setBbsIdx(1);                 // 테스트용

                  bbsDataController.getBbsDataItem(bean);

    }   

 

bbsid, bbsidx 를 입력한 후

 

JUnit Test 를 수행하면 오류 없이 정상적으로 동작된다.

 

P6Spy 로그를 보면

 

bbs_data 쿼리가 수행되기 이전에

bbs_info, bbs_file, bbs_comment 에 각각 쿼리가 수행되는 것을 확인할 수 있다.

 

 

 

복잡한 join 쿼리에 대한 resultMap

복잡한 join 쿼리의 경우 쿼리를 하나씩 수행하기 보다는 한 쿼리에서 결과를 각각 가지고 올 수 도 있다.

 

        

         <resultMap id="bbsDataEx2Result" extends="bbsDataResult" type="BbsDataBean">

                  <association property="bbsInfoBean" column="{bbsId=S_BBS_ID}"select="kr.xboard.dao.bbsinfo.BbsInfoDao.getBbsInfoItem"/>

                  <collection property="bbsFileBeans" ofType="BbsFileBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}" resultMap="kr.xboard.dao.bbsfile.BbsFileDao.bbsFileResult"/>

                  <collection property="bbsCommentBeans" ofType="BbsCommentBean" column="{bbsId=S_BBS_ID,bbsIdx=I_BBS_IDX}"resultMap="kr.xboard.dao.bbscomment.BbsCommentDao.bbsCommentResult"/>          

         </resultMap>

 

         <select id="getBbsDataItem2" parameterType="BbsDataBean" resultMap="bbsDataEx2Result">

                  SELECT *

                    FROM bbs_data a, bbs_file c, bbs_comment d

                   WHERE a.S_BBS_ID = c.S_BBS_ID

                     AND a.I_BBS_IDX = c.I_BBS_IDX

                     AND a.S_BBS_ID = d.S_BBS_ID

                     AND a.I_BBS_IDX = d.I_BBS_IDX

                           <if test="bbsId != null and bbsId != ''">

                                   AND a.S_BBS_ID = #{bbsId}

                           </if>

                           <if test="bbsIdx != null and bbsIdx != ''">

                                   AND a.I_BBS_IDX = #{bbsIdx}

                           </if>              

         </select>        

 

getBbsDataItem2  bbs_data, bbs_file, bbs_comment 를 각각 join 을 해서 결과를 가지고 온다.

resultMap 에서의 차이점은 collection  select attribute  resultMap 으로 변경되었다.


출처 - http://devx.tistory.com/386


==================================================================================

아 .. 정말 

Mybatis 기똥 찼다.. 


필자는 

어떠한 사이트를 처음 혼자 개발 하고 있다. 

HTML, CSS, Controller, DB, Scirpt, 웹디 까지전부.. 

좀 사이즈가 크다 보니 ..  

쿨럭 .. 

게다가 처음인지라 

점점 복잡해 져가는 로직 에 

DB가 문제가 되었다.  

단일 테이블 조회는 상관이 없었지만

여러 테이블 동시에 4개 조인( 너무 정규화를 시켜도 문제다.. 조인이 너무 많아진다. ) 

을 하다보니 

1 : N : M : 1 : 1 연결 에서 

결과값이 List로 불러 오니. 

Controller 단에서 어떻게 처리를 해야 할지. 

괜히 메모리만 잡아 먹는 느낌이 들었다 .

그리고 무분별한 조인으로 DB에 영향이 갈가 걱정되기도 했다 

예를 들어 난 

Object  를 불러 오고 싶었는데 조인을 하다보니 Object가 아닌 Object List가 불러 오는 경우였다..  

무슨 말이냐면 

project {
   private String value1 
   private String value2 
   private Process value3 
}

porcess {
   private String proc1 
   private String proc2 
   private String proc3 
   private Step proc4 
}
Step {
  private String step1
  private String step2 


이런식에 DTO가 있을시 
DB에조인을 해서 이러한 연관 관계를 어떻게 

잘 ~ 이쁘게 넣느냐 가 나의 관점이었다.  

결국 뻘짓과 삽질에 반복으로 해결할 수 있었다. 
바로 ResultMap 과 association , collection 의 조화 였다. 아.. 

아름다워라 

이제 서로 닥치고 본론으로 가겠다. 

<select id="getProject" resultMap="ProjectMaxAll" parameterType="string">
  select 
   prj_name, prj_desc, prj_start, 
   proc_idx, max(proc_step) as proc_step, proc_memo, proc_expire, proc_regdate
  from 
   project
  left join process on prj_name = proc_prj_name
  where
   prj_name = #{prj_name} 
 </select>


 <!-- 프로세스 , 속한 고객정보 가져오기 -->
 <select id ="getProcess" resultMap="ProcessAll" parameterType="string">
  select 
   proc_idx, proc_step, proc_memo, proc_expire, proc_regdate
  from 
   process
  where
   proc_idx = #{proc_idx} 
 </select>
<!--  프로젝트의 프로세스 단계 리스트  -->
 <select id="procStepList"  resultType="Step" >
  select 
   step_idx, step_cust_idx, cust_name, comp_name, cust_cellphone
  from 
   step_company 
  left join customer 
   on step_cust_idx = cust_idx 
  left join company 
   on cust_comp_idx = comp_idx
  where
   step_proc_idx = #{proc_idx}
 </select>
 
 <!--  프로세스의 고객 정보 리스트 -->
 <select id="StepList"  resultType="StepLevel" >
  select 
   proc_idx as step_proc_idx, step_title 
  from process
   left join step on step_value = proc_step
  where 
   proc_prj_name = #{proc_prj_name}
 </select>


 <resultMap id="ProjectMaxAll" type="Project" >
  <id property="prj_name" column="prj_name"/>
  <result property="prj_desc" column="prj_desc"/>
  <result property="prj_start" column="prj_start"/>
  <!-- 프로세스 목록 조회 ProcessAll -->
  <association property="proc" column ="proc_idx" javaType="PrjProcess" resultMap="ProcessAll"/>
 
  <!-- 프로젝트 프로세스 목록 조회 -->
  <association property="stepLevel" column ="prj_name" javaType="ArrayList"
  select="StepList">
   <id property="step_proc_idx" column="step_proc_idx" />
   <result property="step_title" column="step_title" />
  </association>
 </resultMap>
 
 <!-- 프로세스 조회  시작 -->
 <resultMap id="ProcessAll" type="PrjProcess" >
   <id property="proc_idx" column="proc_idx"/>
   <result property="proc_step" column="proc_step"/>
   <result property="proc_memo" column="proc_memo"/>
   <result property="proc_expire" column="proc_expire" />
   <result property="proc_regdate" column="proc_regdate" /> 
   <!-- Step Company 조회 -->
   <association property="prj_proc_stepList"  column="proc_idx" javaType="ArrayList"
    select="procStepList">
    <id property="step_idx" column="step_idx" />
    <result property="step_cust_idx" column="step_cust_idx" />
    <result property="cust_name" column="cust_name" />
    <result property="comp_name" column="comp_name" />
    <result property="cust_cellphone" column="cust_cellphone" /> 
    
   </association> 
 </resultMap>


복잡한가? 실로 그러치 않더라. 

정말 이번걸 보면서 DTO가 얼마나 중요한지 깨달았다.  

처음에 하나에 DTO다 때려 넣었다가. 

이렇게도 된다는 점이 너무 행복했다. 

그리고 이렇게 가지고 온 값을 

쉽게 뿌릴 수 있는 Spring Form 태그에 감사한다.


출처 - http://pikasoo.egloos.com/502488




'Framework & Platform > mybatis' 카테고리의 다른 글

mybatis 3 settings 예제  (0) 2012.04.30
mybatis password 암호화/복호화  (0) 2012.04.28
mybatis 설치 예제  (0) 2012.03.18
ibatis vs MyBatis  (0) 2012.03.15
ibatis 문법 정리  (0) 2012.03.14
Posted by linuxism
,