이클립스를 실행합니다.
퍼스펙티브는 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 |