Spring/10. Mybatis 프레임워크

Day 75 : 스프링과 MyBatis 연동

pancakemaker 2022. 2. 3. 13:00

1. 라이브러리 내려받기

: 스프링과 MyBatis의 연동을 위해 org.mybatis.spring.SqlSessionFactoryBean org.mybatis.spring.SqlSessionTemplate 클래스를 이용

 

- pom.xml 파일 수정 (<dependency> 추가)

		<!-- Mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.3.1</version>
		</dependency>
		
		<!-- Mybatis Spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.4</version>
		</dependency>

 

2. Mybatis 설정 파일 작성

- sql-map-config.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>
	<!-- Alias 설정 -->
	<typeAliases>
		<typeAlias type="com.springbook.biz.board.BoardVO" alias="board"/>
	</typeAliases>

	<!-- SQL Mapper 설정 -->
	<mappers>
		<mapper resource="mappings/board-mapping.xml"/>
	</mappers>
</configuration>

 

- board-mappings.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 : 루트 엘리먼트 -->
<mapper namespace="BoardDAO">
	<resultMap id="boardResult" type="board">
		<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" 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" parameterType="board">
		<![CDATA[
		UPDATE BOARD SET TITLE = #{title}, CONTENT = #{content} WHERE SEQ = #{seq}
		]]>
	</update>
	
	<delete id="deleteBoard" parameterType="board">
		<![CDATA[
		DELETE BOARD WHERE SEQ = #{seq}
		]]>
	</delete>
	
	<select id="getBoard" parameterType="board" resultMap="boardResult">
		<![CDATA[
		SELECT * FROM BOARD WHERE SEQ = #{seq}
		]]>
	</select>
	
	<select id="getBoardList" parameterType="board" resultMap="boardResult">
		<![CDATA[
		SELECT * FROM BOARD
		WHERE TITLE LIKE '%'||#{searchKeyword}||'%'
		ORDER BY SEQ DESC
		]]>
	</select>	
</mapper>

 

3. 스프링 연동 설정

: 스프링 설정 파일에 SqlSessionFactoryBean 클래스를 <bean> 등록

: Mybatis를 이용하려면 SqlSession 객체가 필요한데, SqlSession 객체는 ②SqlSessionFactoryBean 클래스로 SqlSessionFactory 객체를 생성(SqlSessionFactoryBuilder 클래스의 build() 메소드 이용)한 후 ③SqlSessionFactory 객체의 openSession() 메소드를 이용하여 얻을 수 있음

→ SqlSessionFactoryBean 클래스는 Mybatis에서 제공하므로 별도의 작성은 필요 없고, 스프링 설정 파일에서 <bean> 등록만 해주면 됨

 

- 스프링 설정 파일 (applicationContext.xml)

	<!-- Mybatis 연동을 위한 SqlSessionFactoryBean 클래스 등록 -->
	<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:sql-map-config.xml" />
	</bean>

 

4. DAO 클래스 구현 - 방법1 : SqlSessionDaoSupport 클래스 구현

package com.springbook.biz.board.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.springbook.biz.board.BoardVO;

@Repository 	//데이터베이스 연동을 처리하는 DAO 클래스
public class BoardDAOMybatis extends SqlSessionDaoSupport {
	@Autowired	
	//스프링 컨테이너가 해당 메소드 자동 호출 (스프링 설정 파일에 <bean> 등록된 SqlSessionFactoryBean 객체를 인자로 받음)
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		super.setSqlSessionFactory(sqlSessionFactory);
	}
	
	public void insertBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 insertBoard() 기능 처리");
		getSqlSession().insert("BoardDAO.insertBoard", vo);
	}
	
	public void updateBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 updateBoard() 기능 처리");
		getSqlSession().update("BoardDAO.updateBoard", vo);
	}
	
	public void deleteBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 deleteBoard() 기능 처리");
		getSqlSession().delete("BoardDAO.deleteBoard", vo);
	}
	
	public BoardVO getBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 getBoard() 기능 처리");
		return (BoardVO) getSqlSession().selectOne("BoardDAO.getBoard", vo);
	}
	
	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("===> Mybatis로 getBoardList() 기능 처리");
		return getSqlSession().selectList("BoardDAO.getBoardList", vo);
	}	
}

 

5. DAO 클래스 구현 - 방법2 : SqlSessionTemplate 클래스를 <bean> 등록하여 사용

- 스프링 설정 파일 (applicationContext.xml) 수정

	<!-- Mybatis 연동을 위한 SqlSessionFactoryBean 클래스 등록 -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:sql-map-config.xml" />
	</bean>	
	
	<bean class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSession"></constructor-arg>
	</bean>

→ SqlSessionTemplate 클래스는 Setter 메소드가 없어서 Setter 인젝션할 수 없음. 따라서 생성자 메소드를 이용한 Constructor 주입으로 처리해야 함. 또한 DAO 클래스 구현시 @Autowired 어노테이션을 이용하여 SqlSessionTemplate 객체를 의존성 주입 처리해야 함

 

- DAO 클래스

package com.springbook.biz.board.impl;

import java.util.List;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.springbook.biz.board.BoardVO;

@Repository 	//데이터베이스 연동을 처리하는 DAO 클래스
public class BoardDAOMybatis {
	@Autowired	
	//스프링 컨테이너가 해당 객체 자동 호출
	private SqlSessionTemplate mybatis;
	
	public void insertBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 insertBoard() 기능 처리");
		mybatis.insert("BoardDAO.insertBoard", vo);
	}
	
	public void updateBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 updateBoard() 기능 처리");
		mybatis.update("BoardDAO.updateBoard", vo);
	}
	
	public void deleteBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 deleteBoard() 기능 처리");
		mybatis.delete("BoardDAO.deleteBoard", vo);
	}
	
	public BoardVO getBoard(BoardVO vo) {
		System.out.println("===> Mybatis로 getBoard() 기능 처리");
		return (BoardVO) mybatis.selectOne("BoardDAO.getBoard", vo);
	}
	
	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("===> Mybatis로 getBoardList() 기능 처리");
		return mybatis.selectList("BoardDAO.getBoardList", vo);
	}	
}

 

6. Mybatis가 지원하는 Dynamic SQL로 검색 처리

- Dynamic SQL 적용 전 - 두 개의 쿼리 존재, 쿼리문의 개수 만큼 분기 처리 로직 추가 필요 - 유지보수 용이X

private final String BOARD_LIST_T = "select * from board where title like '%'||?||'%' order by seq desc";
private final String BOARD_LIST_C = "select * from board where content like '%'||?||'%' order by seq desc";

	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("===> JDBC로 getBoardList() 기능 처리");
        
		//"제목"으로 검색 시
		if(vo.getSearchCondition().equals("TITLE")) {
			stmt = conn.prepareStatement(BOARD_LIST_T);
		//"내용"으로 검색 시
		} else if(vo.getSearchCondition().equals("CONTENT")) {
			stmt = conn.prepareStatement(BOARD_LIST_C);
		}
	}

- board-mapping.xml 수정 - <if> 조건에 따른 분기 처리 - 유지보수 용이

~ 생략 ~

	<select id="getBoardList" parameterType="board" resultMap="boardResult">
		SELECT * FROM BOARD WHERE 1=1
		<if test="searchCondition == 'TITLE'">
			AND TITLE LIKE '%'||#{searchKeyword}||'%'
		</if>
		<if test="searchCondition == 'CONTENT'">
			AND CONTENT LIKE '%'||#{searchKeyword}||'%'
		</if>
		ORDER BY SEQ DESC
	</select>

~ 생략 ~