본문 바로가기
👨‍💻 2. 웹개발_Back end/2-6 Spring

[Spring] 2장 Mapper XML 파일 설정 - Mybatis 구조와 Mapper XML 파일 구조 및 엘리먼트(select, insert, update, delete), 속성들(parameterType, resultType, resultMap)

by 달님🌙 2021. 11. 2.
반응형

<sql-map-config.xml>

실습 코드 참조

 

moonhy7/SpringFramework: Spring Framework 실습 코드 정리 (github.com)

 

GitHub - moonhy7/SpringFramework: Spring Framework 실습 코드 정리

Spring Framework 실습 코드 정리. Contribute to moonhy7/SpringFramework development by creating an account on GitHub.

github.com

 

 

2.1절 SQL Mapper XML 기본 설정

 

1. Mybatis 구조

 

- SqlMapConfig.xml : Mybatis 메인 환경설정 파일

- Mybatis는 이 파일을 읽어들여 어떤 DBMS와 커넥션을 맺을지, 어떤 SQL Mapper XML 파일들이 등록되어 있는지 알 수 있다.

- Mybatis는 SqlMap.xml 파일에 등록된 각 SQML 명령어들을 Map 구조로 저장하여 관리한다.

 

2. Mapper XML 파일 구조

 

<?xml version="1.0" encoding="UTF-8" ?>
<!-- mapper DTD 선언 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- SQL Mapping -->
<mapper namespace="BoardDAO">
	<insert id="insertBoard"></insert>
	<update id="updateBoard"></update>
 	<delete id="deleteBoard"></delete>
 	<select id="getBoard" resultType="board"></select>						
 	<select id="getBoardList" resultMap="boardResult"></select>
</mapper>

- Mybatis 프레임워크에서 가장 중요한 파일은 SQL 명령어들이 저장되는 SQL Mapper XML (=Mapper) 파일이다.

- Mapper는 <mapper>를 루트 엘리먼트로 가지며 DTD 선언부와 SQL Mapping부로 나뉜 구조를 갖는다.

 

- 네임스페이스를 이용하여 유일한 SQL 아이디를 만들어 DAO 클래스에 참조할 때 위와 같이 참조하면 된다.

 

- 만약 네임스페이스나 아이디 입력을 다르게 하면 아래와 같이 에러가 발생한다.

 

3. <select> 엘리먼트

 

- <select> 엘리먼트는 데이터를 조회하는 SELECT 구문을 작성할 때 사용하며 parameterType과 resultType 속성을 사용할 수 있다.

1) id 속성 

- <select> 엘리먼트에 선언된 id 속성은 필수 속성으로, Mapper 파일들 내에서 유일한 아이디를 등록해야 한다.

- 그래야 나중에 DAO 클래스에서 특정 아이디로 등록된  SQL을 실행 할 수 있다 .

- 이 id 속성과 관련하여 살펴볼 것이 루트 엘리먼트인 <mppaer>이다.

- <mapper> 엘리먼트 안에서 선언된 여러 아이디를 하나의 네임 스페이스로 묶을수 있다.

- 예를 들어 , 다음 두 파일에 선언된 “getTotalCount”라는 아이디는 네임 스페이스가 다르므로 다른 아이디로 처리 될 수있다.

2) parameterType 속성

- Mapper 파일에 등록된 SQL을 실행하려면 SQL에 실행에 필요한 데이터를 외부로 부터 받아야한다.

- 이때 사용하는 속성이  parameterType 속성이다. paramerterType 은 일반적으로 기본형이나 VO형태 클래스를 사용한다.

- 이때 Mybatis  메인 설정파일(sql-map-config.xml)에 등록된<typeAlias>의 Alias를 사용하면 설정을 더 간결하게 처리할 수 있다.

<sql-map-config.xml>

<board.mapping.xml>

 

3) resultType 속성

- 검색 관련 SQL 구문이 실행되면 ResultSet이 리턴되며, ResultSet에 저장된 검색 결과를 어떤 자바 객체에 매핑할지 지정할 때 사용하는 속성이다.

 

<sql-map-config.xml>

<board.mapping.xml>

 

- resultType 속성은 당연히 쿼리 명령어가 등록되는 select 엘리먼트에서만 사용이 가능하다.

-  parameterType 속성과 달리 절대 생략할 수 없는 속성이다.

- 뒤에 나올 resultMap 속성으로 대체가 가능하다.

 

4. <insert> 엘리먼트

 

- 자식 요소로 <selectKey> 엘리먼트를 가질 수 있다.

<insert id="insertBoard">
  INSERT INTO BOARD(
    SEQ
    , TITLE
    , WRITER
    , CONTENT
  )
  VALUES(
    #{seq}
    ,  #{title}
    ,  #{writer}
    ,  #{content}	
  )
</insert>

 

5. <update> 엘리먼트

 

<update id="updateBoard">
  UPDATE BOARD
    SET	
      TITLE = #{title}
      ,  CONTENT = #{content}
    WHERE SEQ = #{seq}
</update>


6. <delete> 엘리먼트

 

<delete id="deleteBoard">
  DELETE FROM BOARD
  WHERE SEQ = #{seq}
</delete>

 

 

2.2절 SQL Mapper XML 추가 설정

 

1. resultMap 속성 사용

 

- 검색 결과를 특정 자바 객체에 매핑하여 리턴하기 위해 parameterType 속성을 사용한다. 

- 하지만 검색 쿼리가 단순 테이블 조회가 아닌 JOIN 구문을 포함할 때는 하나의 자바 객체로 매핑할 수 없다.

- 또한 검색된 테이블의 컬렴명과 매핑될 자바 객체의 변수 이름이 다를 때 매핑되지 않는다.

- 이럴 때 resultMap 속성을 처리하면 된다.

<?xml version="1.0" encoding="UTF-8" ?>
<!-- mapper DTD 선언 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="BoardDAO">
	<resultMap type="board" id="boardResult">
		<id property="seq" column="SEQ"/>
		<result property="title" column="TITLE"/>
		<result property="writer" column="WRITER"/>
		<result property="content" column="CONTENT"/>
		<result property="regDate" column="REGDATE"/>
		<result property="cnt" column="CNT"/>
	</resultMap>
		
 	<select id="getBoardList" resultMap="boardResult">					
 		SELECT * FROM BOARD	
 			WHERE TITLE LIKE CONCAT_WS('%', #{searchKeyword}, '%')
 			ORDER BY SEQ DESC
 	</select>
</mapper>

- resultMap 설정은 PK에 해당하는 SEQ 컬럼만 id 엘리먼트를 사용했고 나머지는 result 엘리먼트를 사용하여 검색 결과로 얻어낸 컬럼의 값과 BoardVO 객체의 변수를 매핑하고 있다.

- 이렇게 설정된 resultMap은 getBoardList로 등록된 쿼리에서 resultMap 속성으로 참조하고 있다.

 

2. CDATA Section 사용

 

- sql 구문 내에서 쓰는 태그로서 <>를 구분하기 위해 사용한다.

- 원리 : 단순한 문자 데이터인 Character DATA로 작성되어 XML 파서가 해석하지 않도록 한다.

- 나중을 위해 모든 SQL 구문을 CDATA Section으로 처리한다.

<select id="getBoard" resultType="board">
  <![CDATA[
    SELECT * FROM BOARD
    WHERE SEQ = #{seq}
  ]]>
</select>

 

3. SQL 대문자로 설정하기

 

- 파라미터들을 바인딩할 때 대부분 칼럼명과 변수명이 같으므로 SQL 구문이 조금이라도 복잡해지면 이 둘을 구분하기가 쉽지 않으므로 SQL은 모두 대문자로 표현해준다.

 

4. 최종 Mapper 파일

 

<?xml version="1.0" encoding="UTF-8" ?>
<!-- mapper DTD 선언 -->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- mapper 자체가 DAO 분리되어 나온 개념이기 때문에 namespace는 DAO 명을 따라가는 경우가 일반적임 -->
<mapper namespace="BoardDAO">
	<resultMap type="board" id="boardResult">
		<id property="seq" column="SEQ"/>
		<result property="title" column="TITLE"/>
		<result property="writer" column="WRITER"/>
		<result property="content" column="CONTENT"/>
		<result property="regDate" column="REGDATE"/>
		<result property="cnt" column="CNT"/>
	</resultMap>

	<insert id="insertBoard">
	<!-- <selectKey keyProperty="seq" resultType="int">
		SELECT BOARD_SEQ.NEXTVAL AS SEQ FROM DUAL
	</selectKey>
	// #{seq} : 사용자 입력 값 or VO에서 가져온 값을 의미 -->
		<![CDATA[
		INSERT INTO BOARD(
						  SEQ
						, TITLE
						, WRITER
						, CONTENT
						)
					VALUES(
							   #{seq}
							,  #{title}
							,  #{writer}
							,  #{content}	
						)
		]]>
	</insert>
	
	<update id="updateBoard">
		<![CDATA[
		UPDATE BOARD
			SET	
				TITLE = #{title}
			 ,  CONTENT = #{content}
			 WHERE SEQ = #{seq}
		]]>
 	</update>
 	
 	<delete id="deleteBoard">
 		<![CDATA[
		DELETE FROM BOARD
			 WHERE SEQ = #{seq}
		]]>
 	</delete>
 	
 	<select id="getBoard" resultType="board">
 		<![CDATA[
 		SELECT * FROM BOARD
 			WHERE SEQ = #{seq}
 		]]>
 	</select>
 	 						
 	<!-- <select id="getBoardList" resultType="board" parameterType="com.springbook.biz.board.BoardVO"> -->
 					<!-- 파라미터타입 : sql-map에서 typeAlias를 주었기 때문에 그냥 board라고 써도 됨 -->
 	<!-- <select id="getBoardList" resultType="board" parameterType="board"> -->		
 	<select id="getBoardList" resultMap="boardResult">					
 		<![CDATA[
 		SELECT * FROM BOARD	
 			WHERE TITLE LIKE CONCAT_WS('%', #{searchKeyword}, '%')
 			ORDER BY SEQ DESC
 		]]>
 	</select>
</mapper>

 

 

2.3절 Mybatis JAVA API

 

1. SqlSessionFactoryBuilder 클래스

 

- Mybatis Mapper 설정이 끝나고 이제 Mybatis 프레임워크에서 제공하는 API를 이용해서 DAO 클래스를 구현해야한다.

- Mybatis로 DAO 클래스의 CRUD 메소드를 구현하려면 Mybatis 에서 제공하는 SqlSession 객체를 사용해야 한다.

- 그런데 SqlSession 객체는 SqlSessionFactory로부터 얻어야 하므로 가장 먼저 해야할 작업은 Sql SessionFactory 객체를 생성하는 일이다.

- SqlSessionFactory 객체를 생성하려면 Sql SessionFactoryBuilder 의 Build() 메소드를 이용하는데, build() 메소드는 MyBatis 설정파일( sql-map-config.xml)을 로딩하여 SqlSessionFactory 객체를 생성한다

- 그리고 sql-map-config.xml 파일을 로딩하려면 입력 스트림인 Reader 객체가 필요하다 

Reader 객체는 Resources 클래스의 getResourceAsReader() 메소드를 사용하여 얻어낼수 있다,

 

- 다음은 SqlSessionFactory 객체를 생성하는데 사용된 자바 코드다.

Reader reader = Resources.getResourceAsReader(”sql-map-config.xml”);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

 

2. SqlSessionFactory 클래스

 

- SqlSessionFactory는 이름에서 알수 있듯이 SqlSession 객체에 대한 공장 역할을 수행한다.

- SqlSessionFactory 객체는 openSession()이라는 메소드를 제공하며, 이 메소드를 이용해서 SqlSession 객체를 얻을 수 있다.

- 이렇게 얻어낸 SqlSession 객체를 통해 다음과 같이 글 등록 기능을 처리할 수 있다.

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
SqlSession session = sessionFactory.openSession();
session.insert("BoardDAO.insertBoard", vo);

 

3. 유틸리티 클래스 작성

 

- Mybatis를 사용하여 DB 연동을 간단하게 처리하려면 최종적으로 Mybatis가 제공하는 SqlSession 객체를 사용해야한다.

- 따라서 모든 DAO 클래스에서 좀더 쉽게 SqlSession 객체를 획득할 수 있도록 공통으로 제공할 유틸리티 클래스를 만드는 것이다.

- 나중에 스프링과 Mybatis를 연동할 때는 프레임워크에서 제공하는 클래스를 사용하면 된다.

package com.springbook.biz.util;

import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class SqlSessionFactoryBean {
	private static SqlSessionFactory sessionFactory =null;
	
	static {
		try {
			if(sessionFactory == null) {
				Reader reader = Resources.getResourceAsReader("sql-map-config.xml");
				sessionFactory = new SqlSessionFactoryBuilder().build(reader);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
	public static SqlSession getSqlSessionInstance() {
		return sessionFactory.openSession();
	}
}

 

4.SqlSession 객체

 

- SqlSession 객체는 Mapper XML에 등록된 SQL을 실행하기 위한 다양한 API를 제공한다.

package com.springbook.biz.board.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.springbook.biz.board.BoardVO;
import com.springbook.biz.util.SqlSessionFactoryBean;

public class BoardDAO {
	private SqlSession mybatis;
	
	public BoardDAO() {
		mybatis = SqlSessionFactoryBean.getSqlSessionInstance();
	}
	
	public void insertBoard(BoardVO vo) {
		mybatis.insert("BoardDAO.insertBoard", vo); // 네임스페이스.아이디 형태로 mapper에 있는 쿼리문을 호출할 수 있다.
		mybatis.commit();		//HashMap, Map, List, Integer, String
	}
	
	public void updateBoard(BoardVO vo) {
		mybatis.update("BoardDAO.updateBoard", vo);
		mybatis.commit();
	}
	
	public void deleteBoard(BoardVO vo) {
		mybatis.delete("BoardDAO.deleteBoard", vo);
		mybatis.commit();
	}
	
	public BoardVO getBoard(BoardVO vo) {
		return (BoardVO) mybatis.selectOne("BoardDAO.getBoard", vo);
	}
	
	public List<BoardVO> getBoardList(BoardVO vo) {
		return mybatis.selectList("BoardDAO.getBoardList", vo);
	}
}

 

 

 

반응형

댓글