본문 바로가기
Programming/Spring

Mybatis

by TinKerBellBass 2017. 8. 13.
728x90
반응형
참고 도서
스프링 퀵 스타트
국내도서
저자 : 채규태
출판 : 루비페이퍼 2016.06.30
상세보기



1. Mybaits?

마이바티스는 SQL 명령어를 자바 코드에서 분리하여 XML로 관리하기 위한 프레임워크로,
XML에 설정한 SQL 명령어를 대신 실행하고 실행 결과를 VO 같은 자바 객체에 자동으로 매핑해 준다.

마이바티스 구조는 요렇게 생겼다.

SqlMapConfig.xml 은 마이바티스 환경설정파일로, 마이바티스는 이 파일을 읽어 어떤 DMBS와 커넥션을 연결할지, 

어떤 SQL Mapper XML 파일들이 등록되어 있는지 알아낸다.

SqlMap.xml 은 등록된 각 SQL 명령어들을  Map 구조로 저장하여 관리한다.

즉, 각각의 SQL 명령어가 가지는 아이디를 중복 없이 Map의 키값으로 등록한다. 

그리고 SQL 이 실행될 때 필요한 값들을 input 형태의 데이터로 할당하고,

SQL 이 SELECT 일 때는 output 형태의 데이터로 리턴한다.


2. Mybatis 환경설정 파일

① Maven Repository 에서 사용할 DB, mybatis, mybaits spring 을 검색하여, pom.xml 에 설정하고 라이브러리 다운
② 이클립스나 STS를 열고 마켓플레이스에서 Java ORM 를 검색해 플러그인 설치
③ 프로젝트에서 오른쪽 마우스 버튼 클릭, New - Other -> Java ORM Plugin 폴더 안의 Mybatis Configuration XML 선택
(적당히 이름 적어서 파일 생성, 보통은 sql-map-config.xml 로 사용)
④ 파일 관리를 위해 src 에 생성된 파일을 src/main/resource 폴더로 이동
⑤ 환경 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<configuration>
    <!-- Alias 설정 -->
    <typeAliases>
        <!-- alias(별명, 별칭), typeAlias는 여러개 등록 가능 -->
        <!-- com.neverland.mybaits.board 패키지의 BoardVO 클래스를 board 별명으로 설정 -->
         <!-- SQL Mapper 에서 사용 -->
        <typeAlias type="com.neverland.mybatis.board.BoardVO" alias="board"></typeAlias>
    </typeAliases>
 
    <!-- Sql Mapper 설정 -->
    <!-- 여러개의 Mapper 등록 가능 -->
    <mappers>
        <mapper resource="mappings/board-mapping.xml" />
    </mappers>
 
<!-- DataSource 설정, Spring 과 연동하는 경우, DB 관련 처리는 Srping 에 맡김 -->

<!-- Mybatis 에서 DataSource 를 설정하고자 하는 경우 -->
<!-- 
<enviroments default="development">
    <enviroment id="development">
        <transaction type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="사용할 DB Driver"/>
            <property name="url" value="사용할 DB url"/>
            <property name="username" value="사용할 DB username"/>
            <property name="password" value="사용할 DB password"/>
        </dataSource>
    </enviroment>
</enviroments>
-->
</configuration>
cs

3. SQL Mapper Elements

(1) <mapper>

 <mapper namespace="MybatisBoardDAO"

     SQL 엘리먼트들...

 </mapper> 

  namespace 속성, DAO 클래스에서 사용할 매퍼 이름


  mapper는 루트 엘리먼트로 여러개 등록 가능

  SQL 엘리먼트는 유일한 값인 id 속성을 가지는데, 소속된 mapper 엘리먼트가 다르면 같은 id 사용 가능


 에러 남

 <mapper>

     <insert id="BoardGoGo">

     <delete id="BoardGoGo">

 </mapper>


 에러 안 남

 <mapper>

     <insert id="BoardGoGo">      

 </mapper>

 <mapper>

     <insert id="BoardGoGo">      

 </mapper> 


(2)  <select>

 <select id="getBoard" parameterType="board" resultType="board">

     SELECT * FROM BOARD WHERE SEQ=#{seq}

 </select>  

 id 속성(모든 SQL 엘리먼트 동일)

 필수 속성, DAO 클래스에서 id 로 SQL 실행할 때 사용

 ex) DAO 클래스, mybaits.selectOne("MybatisBoardDAO.getBoard", vo)

      MybatisBoardDAO -> mapper 의 namespace / getBoard -> SQL 엘리먼트의 id


 parameterType 속성

 SQL 실행에 필요한 데이터 설정, 생략 가능(대부분 생략)

 ex) ① parameterType="com.neverland.mybatis.board.BoardVO"

      ② 마이바티스 설정파일에 설정한

          <typeAlias type="com.neverland.mybaits.board.BoardVO" alias="board"/>

          alias="board" 사용, parameterType="board"


 resultType 속성

 결과가 필요한 검색 관련 SQL 이 실행될 때, 리턴되는 검색 결과를 자바 객체에 매핑(필수 속성)

 ex) ① resultType="com.neverland.mybatis.board.BoardVO"

      ② 마이바티스 설정파일에 설정한

          <typeAlias type="com.neverland.mybaits.board.BoardVO" alias="board"/>

          alias="board" 사용, resultType="board"


(3) <insert>


 <insert id="insertBoard">

     <selectKey keyProperty="seq" resultType="int">

          SELECT BOARD_SEQ.NEXTVAL AS seq from DUAL

     INSERT INTO BOARD(SEQ, TITLE, CONTENT)

     VALUES(#{seq}, #{title}, #{content})

 </insert>     

 <selectKey> 자식 엘리먼트(생략 가능)

  auto increment 가 없는 오라클은 시퀸스로 자동 증가 사용, 이 경우 사용(보통은 자동 증가 없이, 서비스나 컨트롤에서 구현)

  BOARD_SEQ 라는 시퀸스로부터 킷값을 얻어와 seq 로 명명, INSERT INTO 구문에서 사용


(4) <update>, <delete>


 <update id="updateBoard">

     UPDATE BOARD SET TITLE=#{title}, CONTENT=#{content}

     WHERE SEQ=#{seq}

 </update> 

 <delete id="deleteBoard">

     DELETE BOARD WHERE SEQ=#{seq}

 </delete>


(5) <resultMap>


 <resultMap id="boardResult" type="board">

     <id property="seq" column="SEQ"/>

     <result property="title" column="TITLE"/>

     <result property="content" column="CONTENT"/>

 </resultMap>


 <select id="getBoardList" resultMap="boardResult">

     select * from board order by desc

 </select>    

 JOIN 의 경우처럼 검색 결과를 정확하게 하나의 자바 객체로 매핑할 수 없거나(조인 했으니까 테이블 2개, VO 2개),

 테이블의 칼럼이름과 매핑에 사용될 자바 객체의 변수 이름이 다를 때 사용


 select 엘리먼트의 resultMap 속성 값 => resultMap 의 id 속성 값 


(6) CDATA Section 사용 및 SQL 대문자로 설정


XML 문법인 CDATA 사용, CDATA 영역 안의 데이터는 단순한 문자 데이터로 

 XML 파서가 해석하지 않아서, 그대로 DB에 전달 됨

 

 만약 SELECT * FROM BOARD WHERE SEQ <= #{seq} 같은 쿼리문이 있다면

 XML 에서 < 와 > 기호는 태그 기호로 인식하기 때문에 에러 발생, XML 파서가 해석하지 못하게 하면 해결됨

 ex)  <delete id="deleteBoard">

            <![CDATA[

                  DELETE BOARD WHERE SEQ=#{seq}

            ]]>

       </delete>

 DB 는 대소문자 구분을 하지 않기 때문에, 

 식별성을 높이고, 변수명과 확실히 구분하기 위해 SQL 구문은 보통 대문자로 작성


(7) 실제 작성 예
① 프로젝트에서 마우스 오른쪽 버튼 클릭, New - Other -> Java ORM Plugin 폴더 안의 Mybatis Mapper XML 선택
    (원하는 이름으로 SQL Mapper 파일 생성)
② 파일 관리를 위해 src 폴더 안에 생성된 SQL Mapper 파일을 src/main/resources/mappings 폴더로 이동

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!-- src/main/resources/mappings/board-mapping.xml -->
<mapper namespace="BoardDAO">
    <resultMap id="boardResult" type="board">
        <id property="seq" column="SEQ" />
        <id property="title" column="TITLE" />
        <id property="writer" column="WRITER" />
        <id property="content" column="CONTENT" />
        <id property="regDate" column="REGDATE" />
        <id property="cnt" column="CNT" />
    </resultMap>
 
    <insert id="insertBoard" parameterType="board">
        <![CDATA[
        INSERT INTO BOARD(SEQ, TITLE, WRITER, CONTENT)
        VALUES((select nvl(max(SEQ),0)+1 from board),#{title},#{writer},#{content})
        ]]>
    </insert>
 
    <update id="updateBoard">
        <![CDATA[
        UPDATE BOARD SET TITLE=#{title},CONTENT=#{content} WHERE SEQ=#{seq}
        ]]>
    </update>
 
    <delete id="deleteBoard">
        <![CDATA[
        DELETE BOARD WHERE SEQ=#{seq}
        ]]>
    </delete>
 
    <select id="getBoard" resultType="board">
        <![CDATA[
        SELECT * FROM BOARD WHERE SEQ=#{seq}
        ]]>
    </select>
 
    <select id="updateCnt">
    <![CDATA[
    UPDATE BOARD SET CNT=#{cnt}+1 WHERE SEQ=#{seq}
    ]]>
    </select>
 
    <select id="getBoardList" resultType="board">
        <![CDATA[
        SELECT * FROM BOARD
        ]]>        
    </select>
</mapper>
cs



4. 스프링 연동 설정

비지니스 컴포넌트를 관리하는 스프링 컨테이너 설정 파일(applicationContent.xml)에 마이바티스 설정

1
2
3
4
5
6
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!--org.apache.commons.dbcp.BasicDataSource 로 생성한 dataSource  -->
    <property name="dataSource" ref="dataSource"/>
    <!-- 마이바티스 환경설정 파일 주입-->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
cs

DAO에서 DB 처리에 사용할 SqlSession 객체는 SqlSessionFactoryBean 클래스에서 얻을 수 있기 때문에,
SqlSessionFactoryBean 객체 생성 

5. DAO 구현(SqlSessionDaoSupport 클래스 상속)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// SqlSessionDaoFactory 상속
@Repository
public class BoardDAOMybatis extends SqlSessionDaoSupport {
    
    // SqlSession 객체를 사용하기 위해
    // bean 으로 등록한 SqlSessionFactoryBean 객체를 인자로 받아
    // 슈퍼클래스인 SqlSessionDaoFactory의 setSqlSessionFactory() 메소드 호출
    //
    // 상속 받은 SqlSessionDaoSupport 클래스 일부
    // public abstract class SqlSessionDaoSupport extends DaoSupport{
    //    
    //    private SqlSession sqlSession; 
    //    SqlSessionFactory 객체를 받아서 sqlSession 객체 생성 
    //      public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    //        if (!this.externalSqlSession) {
    //          this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    //      }
    //    sqlSession 객체가 생성되어야 getSqlSession() 가능
     //    public SqlSession getSqlSession() {    
    //    return this.sqlSession;
    //    }
    // }
    // 
    // SqlSessionFactoryBean 객체가 생성되는 클래스, FactoryBean<SqlSessionFactory> 를 구현하고 있다 
    // public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>{
    //     클래스 내용은 생략         
    // }
    
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    super.setSqlSessionFactory(sqlSessionFactory);
    } 
 
    public void insertBoard(BoardVO vo) {        
        getSqlSession().insert("BoardDAO.insertBoard", vo);
    }
 
    public void updateBoard(BoardVO vo) {        
        getSqlSession().update("BoardDAO.updateBoard", vo);
    }
 
    public void deleteBoard(BoardVO vo) {        
        getSqlSession().delete("BoardDAO.deleteBoard", vo);
    }
 
    public BoardVO getBoard(BoardVO vo) {        
        return getSqlSession().selectOne("BoardDAO.getBoard", vo);
    }
 
    public List<BoardVO> getBoardList(BoardVO vo) {        
        return getSqlSession().selectList("BoardDAO.getBoardList", vo);
    }
 
}
cs


6. DAO 구현(SqlSessionTemplate 클래스 <bean> 등록)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// applicationContext.xml 에 SqlSessionTemplate 클래스 bean 등록
// <bean class="org.mybatis.spring.SqlSessionTemplate">
//        <constructor-arg ref="sqlSession"/>
// </bean>
//
//  SqlSessionTemplate 클래스 일부
//
    // SqlSessionFactoryBean 객체가 생성되는 클래스, FactoryBean<SqlSessionFactory> 를 구현하고 있기 때문에
    // SqlSessionTemplate 클래스 생성자의 SqlSessionFactory 매개변수로 들어갈 수 있다 
    // public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>{
    //     클래스 내용은 생략         
    // }
//  
//  SqlSession을 구현하고 있다
//  public class SqlSessionTemplate implements SqlSession, DisposableBean {
//
//  private final SqlSessionFactory sqlSessionFactory;
//
//  구현하고 있는 SqlSession 을 위임해서(Proxy pattern) DB 처리 
//  private final SqlSession sqlSessionProxy;
//
//    생성자를 통해서 SqlSessionFactory 타입 객체를 받고 있기 때문에
//  bean 객체 등록할 때 constructor-arg 를 통해 주입 해야 한다
//  public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
//    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
//  }
//
//  @Override
//  public <T> T selectOne(String statement) {
//    return this.sqlSessionProxy.<T> selectOne(statement);
//  } 
 
@Repository
public class BoardDAOMybatis {
    @Autowired
    private SqlSessionTemplate mybatis;    
 
    public void insertBoard(BoardVO vo) {        
        mybatis.insert("BoardDAO.insertBoard", vo);
    }
 
    public void updateBoard(BoardVO vo) {        
        mybatis.update("BoardDAO.updateBoard", vo);
    }
 
    public void deleteBoard(BoardVO vo) {
        mybatis.delete("BoardDAO.deleteBoard", vo);
    }
 
    public BoardVO getBoard(BoardVO vo) {    
        return mybatis.selectOne("BoardDAO.getBoard", vo);
    }
 
    public List<BoardVO> getBoardList(BoardVO vo) {        
        return mybatis.selectList("BoardDAO.getBoardList", vo);
    }
 
}
cs

처음에는 이게 뭔 소린가 했지만.. 
역시 이해가 잘 안 될때는... JAR 파일 까서 클래스 다 뜯어보는게 최고인 것 같다...

7. Dynamic SQL(동적 SQL)

동적, 정적이 여기서도 튀어 나와주시는..
정적 - 변화가 없는 / 동적 - 변화가 있는~ 끝!
즉 조건에 맞춰(분기, if) 알맞은 SQL을 실행시키기 위해 지원하는 마이바티스의 기능이 Dynamic SQL이다.

아래 소스는 검색 조건에 맞춰 SQL의 WHERE 절을 다르게 실행한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<select id="getBoardList" resultType="board">
        <![CDATA[
        SELECT * FROM BOARD
        WHERE
        ]]>
        <if test="searchCondition=='TITLE'">
            <![CDATA[
            TITLE LIKE '%'||#{searchKeyword}||'%'
            ]]>
        </if>
        <if test="searchCondition=='CONTENT'">
        <![CDATA[
            AND CONTENT LIKE '%'||#{searchKeyword}||'%'
            ]]>
        </if>
        <![CDATA[
        ORDER BY SEQ DESC;
        ]]>
</select>
cs
 






728x90
반응형

'Programming > Spring' 카테고리의 다른 글

JPA 스프링 연동  (0) 2017.08.14
JPA (Java Persistence API) 기본 개념  (2) 2017.08.13
Spring Layered Architecture  (0) 2017.08.09
Spring MVC (annotation 기반)  (0) 2017.08.08
Spring MVC (XML 설정 기반)  (0) 2017.08.08

댓글