Spring에 MyBatis 연동하기

tabi·2023년 6월 30일
0

Spring

목록 보기
6/15
post-thumbnail

스프링 4버젼에는 MyBatis/iBATIS(MyBatis의 옛날 이름)와의 연동기능이 포함되어 있지 않지만, MyBatis가 제공하는 모듈을 이용해 DataSource 및 트랜잭션 관리 기능을 MyBatis에 적용할 수 있다.

1. MyBatis 연동하기

연동 방법

  • MyBatis-Spring 모듈 추가
  • SqlSessionFactoryBean을 이용해 SqlSessionFactory 설정
  • 트랜잭션 설정
  • MyBatis를 이용한 DAO 구현
    • SqlSession 이용 구현
    • Mapper 동적 생성 이용 구현

1. MyBatis-Spring 모듈 추가

  • pom.xml에 추가해준다.
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis p91-->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.4.6</version>
</dependency>
		
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis-spring</artifactId>
  <!-- mybatis와 spring을 연결하는 역할 -->
	<version>1.3.2</version>
</dependency>

2. SqlSessionFactoryBean과 트랜잭션 관리자 설정

  • 스프링의 DB 관련 기능과 MyBatis를 연동하려면 mybatis-spring 모듈이 제공하는 SqlSessionFactoryBean을 이용해 mybatis의 SqlSessionFactory를 생성해야 한다.
  • root-context.xml 설정
<!-- p91 -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
	  <property name="dataSource" ref="dataSource"></property>
</bean>
  • mapperLocations 프로퍼티는 매핑 쿼리를 담고있는 파일의 목록을 지정한다.
  • dataSource 프로퍼티는 DB 연결을 구할 때 사용할 DataSource를 설정한다.

3. MyBatis를 이용한 DAO 구현

  1. SqlSessionTemplate를 이용한 구현
  • SqlSessionTemplate가 내부적으로 사용하는 SqlSession 프록시 객체가 스프링 연동 처리를 한다.(SqlSessionTemplate가 MyBatis의 SqlSession 인터페이스를 상속받음)
  • SqlSessionTemplate 설정 시에는 SqlSessionTemplate 클래스 생성자에 sqlSessionFactory를 전달해주면 된다.
  • 예시
<bean id = "sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg ref="sqlSessionFactory"/>
</bean>

<bean id = itemDao
      class="패키지명.MyBatisItemDao">
  <property name = "sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
  1. SqlSessionDaoSupport 클래스를 이용한 DAO 구현
  • SqlSessionDaoSupport 클래스는 스프링과 연동된 SqlSession을 제공하는 getSqlSession() 메서드를 포함하므로 하위 클래스는 이 메서드를 이용해 SqlSession에 접근 가능하다.
  • SqlSessionFactory나 SqlSessionTemplate를 설정해주어야 SqlSessionDaoSupport 클래스가 정상 동작한다.
  1. Mapper 동적 생성(자동생성) 이용 구현
  • 스프링에서 개별 매퍼 인터페이스로부터 DAO 빈 객체를 생성하려면 MapperFactoryBean 클래스를 사용하면 된다.
<bean id = "purchaseOrderDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name = "mapperInterface"
      value = "패키지명.PurchaseOrderDao"/>
  <property name = "sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

4. 스캔을 이용한 매퍼 검색

  • 다수의 매퍼 인터페이스를 검색해 자동으로 빈으로 등록할 때 사용됨

  • DB를 연결해주는 DAO 인터페이스를 만들면 mybatis의 스캔 기능에 의해 자동으로 Bean 객체로 등록된다.

  • 매퍼 스캔 기능을 사용하려면 <mybatis:scan> 태그를 사용한다.

  • root-context.xml에 등록

<mybatis:scan base-package = "패키지 주소"/>

<!-- 예시 -->
<mybatis-spring:scan base-package="org.doit.ik.mapper"/>
  • base-package 속성으로 설정한 패키지 및 그 하위 패키지의 모든 인터페이스를 검색해서 매퍼로 등록한다.
  • 생성된 매퍼 빈이 필요한 클래스는 @Autowired나 @Resource 등을 이용해 빈 사용 가능
  • 검색 대상을 제한하고 싶다면 annotation이나 marker-interface 속성을 사용하면 된다.
  • factory-ref와 template-ref를 둘 다 설정할 경우 factory-ref의 설정이 무시됨(두 속성을 모두 설정하지 않은 상태에서 SqlSessionFactory 타입 빈이나 SqlSessionTemplate 타입 빈이 두 개 이상 존재하면 exception 발생)

2. 예시

  1. MemberMapper
  • MemberMapper.java 인터페이스
package org.doit.ik.mapper;

import java.sql.SQLException;

import org.doit.ik.domain.MemberVO;

public interface MemberMapper {
	public MemberVO getMember(String id) throws ClassNotFoundException, SQLException;
	
	public int insert(MemberVO member) throws ClassNotFoundException, SQLException;	
}
  • MemberMapper.xml 구현
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.doit.ik.mapper.MemberMapper">

	<!-- select는 반드시 resultType이 필요 -->
	<select id = "getMember" resultType="org.doit.ik.domain.MemberVO">
	SELECT *
	FROM MEMBER
	WHERE ID = #{id}
	</select>
	
	<insert id = "insert">
	INSERT INTO MEMBER(ID, PWD, NAME, GENDER, BIRTH, IS_LUNAR, CPHONE, EMAIL, HABIT, REGDATE)
	VALUES( #{id}, #{pwd}, #{name}, #{gender}, #{birth}, #{is_lunar}, #{cphone}, #{email}
	, #{habit}, SYSDATE)
	</insert>
</mapper>
  1. NoticeMapper
  • NoticeMapper.java 인터페이스
package org.doit.ik.mapper;

import java.sql.SQLException;
import java.util.List;

import org.doit.ik.domain.NoticeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public interface NoticeMapper {
	
	//검색한 결과의 총 레코드 수를 반환하는 메서드
	public int getCount(String field, String query) throws ClassNotFoundException, SQLException;

	//페이징+공지사항 목록
	public List<NoticeVO> getNotices(int page, String field, String query) throws ClassNotFoundException, SQLException;
	
	//공지사항 삭제
	public int delete(String seq) throws ClassNotFoundException, SQLException;
	
	//공지사항 수정
	public int update(NoticeVO notice) throws SQLException;
	 
	//공지사항 상세보기
	public NoticeVO getNotice(String seq) throws ClassNotFoundException, SQLException;

	//공지사항 작성
	public int insert(NoticeVO notice) throws ClassNotFoundException, SQLException;
	
	/*
	 * //트랜젝션 처리를 하기 위한 메서드 추가 public void insertAndPointUpOfMember(NoticeVO notice,
	 * String id) throws ClassNotFoundException, SQLException;
	 */
	
	void hitUp(String seq);
	
	int getHit(String seq);
}
  • NoticeMapper.xml 구현
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.doit.ik.mapper.NoticeMapper">

	<!-- select는 반드시 resultType이 필요 -->
	<select id = "getCount" resultType="Integer">
	
	<!-- ${전달된 값 그대로 적용} -->
	<!-- #{전달된 값의 자료형에 맞게 변환} -->
	
	SELECT COUNT(*) CNT
	FROM NOTICES
	WHERE ${field} LIKE '%${query}%'
	<!-- field는 첫번째 매개변수라서 ${param1}이라고 쓸 수도 있다. -->
	<!-- query는 두번째 매개변수라서 ${param2}이라고 쓸 수도 있다. -->
	</select>
	
	<select id = "getNotices" resultType="org.doit.ik.domain.NoticeVO">
	<!-- int srow = 1 + (page-1)*15; // 1, 16, 31, 46, 61, ... an = a1 + (n-1)*d  -->
	<!-- int erow = 15 + (page-1)*15; //15, 30, 45, 60, 75, ...  -->
	
	SELECT *
	FROM
		(SELECT ROWNUM NUM, N.*
		FROM (
		SELECT *
		FROM NOTICES
		WHERE ${field} LIKE '%${query}%'
		ORDER BY REGDATE DESC
		) N
	)
	WHERE NUM BETWEEN (1 + (#{page}-1)*15) AND (15 + (#{page}-1)*15)
	<!-- 여기는 전달받은 값이 들어가야 하니까 #{page} 사용 -->
	</select>
	
	<delete id = "delete">
	DELETE
	NOTICES
	WHERE SEQ= #{seq}
	</delete>
	
	<update id = "update">
	UPDATE NOTICES
	SET TITLE= #{title}, CONTENT= #{content}
	<if test="filesrc != null">
	, FILESRC= #{filesrc}
	</if>
	WHERE SEQ= #{seq}
	</update>

	<select id = "getNotice" resultType="org.doit.ik.domain.NoticeVO">
	SELECT *
	FROM NOTICES
	WHERE SEQ= #{seq}
	</select>

	<update id="hitUp">
         UPDATE notices  
       SET hit = hit + 1  
       WHERE seq = #{ seq }
   </update>
 
   <select id="getHit" resultType="Integer">
         SELECT hit  
        FROM notices 
          WHERE seq = #{ seq }
   </select>
   
   <insert id = "insert">
   
   	<selectKey order = "BEFORE" resultType="String" keyProperty="seq">
   	SELECT MAX(TO_NUMBER(SEQ))+1
   	FROM NOTICES
   	</selectKey>
   
   INSERT INTO NOTICES
       ( SEQ, TITLE, CONTENT, WRITER, REGDATE, HIT, FILESRC) 
        VALUES
        ( #{seq}, #{title}, #{content}, #{writer}, SYSDATE, 0, 
        <!-- 첨부된 파일이 없을 경우 처리하는 코드 -->
        #{filesrc, javaType=String,  jdbcType=VARCHAR} )
   </insert>
</mapper>
  1. JoinController.java에서 Bean 객체 주입 수정
	@Autowired
	private MemberMapper memberDao;
  1. CustomerController.java에서 Bean 객체 주입 수정
	@Autowired
	private NoticeMapper noticeDao;
profile
개발 공부중

0개의 댓글