개발이야기/Spring

[Code Lean Spring Web] 4. MyBatis와 Spring 연동

cafe-jun12 2019. 11. 17. 16:05
반응형

이번 블로그에서는 스프링 프레임워크와 Mybatis를 연동해서 좀 더 빠르게 SQL을 처리할수 있는 구조를 설계 해보겠습니다. 

 

MyBatis


MyBatis는 흔히 SQL Mapping 프레임워크로 분류됩니다. 개발자들은 JDBC 사용하는 코드가 복잡하고 지루한 반복작업을 하는것 같아 좀더 빠르고 쉽게 SQL을 사용할수 있는 방법을 찾다가 MyBatis라는 프레임워크를 고안해 냅니다. 전통적인 JDBC 프로그래밍의 구조와 비교해 보면 MyBatis의 장점을 명확이 확인할수가 있습니다. 

 

전통적인 JDBC 프로그램 MyBatis

-직접 Connection을 맺고 마지막에 close()을 해야합니다. 

-PrepareStatement 직접 생생하여 처리 

-PrepareStatement의 setXXX()등에 대한 모든 작업을 개발자가 개발 

-SELECT의 경우 직접 ResultSet처리

- 자동으로 Connection close() 처리

-MyBatis 내부적으로 PreparedStatement 처리 

-#{prop}와 같이 속서을 지정하면 내부적으로 동착 처리 

-리턴 타입을 지정하는 경우 자동으로 객체 생성 및 ResultSet처리 

앞으로 예제에서 사용할 구조는 다음과 같습니다. 

Spring-MyBatis 예제 

 

스프링 프레임워크의 특징중 하나는 다른 프레임워크들을 배척하는 대신에 다른 프레임워크들과의 연동을 쉽게 하는 라이브러리들이 많습니다 MyBatis역시 mybatis-spring이라는 라이브러리를 통해서 쉽게 연동을 할수가 있습니다. 

 

MyBatis 관련 라이브러리 추가 


MyBatis와 mybatis-spring을 사용하기 위해서는 pom.xml파일에 추가적인 라이브러리를 설정해야 합니다. 

<!-- mybatis-spring -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>1.3.2</version>
		</dependency>	
		<!-- mybatis -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.4.6</version>
		</dependency>
		<!-- spring-tx -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-tx</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>
		<!-- spring-jdbc -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>
  • spring-jdbc/spring-tx : 스프링에서 데이터베이스 처리와 트랜젝션 처리 역활 

  • mybatis/mybatis-spring: MyBatis와 스프링 연동용 라이브러리 

pom.xml에 4가지 라이브러리를 추가합니다. 

SQLSeesionFactory


MyBatis에서 가장 핵심적인 객체는 SQLSessionTemplate 이라는 것과 SQLSeesionFactory 입니다. SQLSessionFactory 의 이름에서 알수 있듯이 내부적으로 SQLSessionTemplate 이라는 것을 생성하는 역활을 하는 존재입니다. 개발에서는 SQLSessionTemplate 을 통해서 Connection을 생성하거나 원하는 SQL을 전달하고 결과를 리턴 받는 구조로 설계됩니다. root-context.xml 에서는 다음과 같은 형태로 Mybatis를 설계합니다. 

 

root-context.xml namespace 설정

root-context.xml 파일에서 namespace탭 안에  mybatis-spring을 체크 합니다.그리고 Source 텝으로 들어갑니다.

<!-- Root Context: defines shared resources visible to all other web components -->
	<context:component-scan base-package="com.exe.sample"/>
	
    <!-- mybatis 설정 -->
	<mybatis-spring:scan base-package="com.exe.mapper"/>
	
	
	<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:XE"/>
		<property name="username" value="cafejun"/>
		<property name="password" value="dkagh1"/>
	</bean>
   <!-- HikariCP 설정  -->
	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
		<constructor-arg ref="hikariConfig"/>
	</bean>
	<!-- SQLSession Factory 설정-->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
	</bean>
	<!-- SQLSession Factory 설정-->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="mapperLocations" value="classpath:/TimeMapper.xml"/>
 	</bean>

<mybatis-spring:scan> 태그의 base-package 속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아서 처리합니다. 그 다음으로 XML Mapper와 같이 사용하여 쿼리문을 처리하도록 해보겠습니다. XML Mapper를 사용하는 이유는 어노테이션을 이용하는 방법이 편하기는 하지만 SQL문이 길어지거나 복잡한경우에는 XML 파일에 모아서 처리하는 경우가 관리하기 편합니다. XML을 작성해서 사용할 때에는 XML파일의 위치와 XML 파일에 지정하는 namespace속성이 중요한데 XML파일 위치의 경우 Mapper인터페이스가 있는곳에 같이 작성하거나 'src/main/resources' 구조에 XML을 지정할 폴더를 생성할수가 있습니다. 

 

TimeMapper 테스트 구조 

 

저는 XML 파일의 가독성을 높이기 위해서 Mapper인터페이스와 같은 이름을 사용해 TimeMapper.xml을 생성하였습니다. 그 다음단계로 으로 TimeMapper.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="com.exe.mapper.TimeMapper">
 	<select id="getTime2" resultType="string">
 		SELECT sysdate FROM DUAL
 	</select>
 </mapper> 
 

저는 Mapper을 이용하기 위해서 인터페이스를 다음과 같이 만들었습니다. 

package com.exe.mapper

import org.apache.ibatis.annotations.Select;

public interface TimeMapper {

	//어노테이션을 통한 SQL문 작성 
	@Select("SELECT sysdate FROM DUAL")
    public Sttring getTime();
    //XML Mapper를 이용한 SQL문 이용 
    public String getTime2();

}

위 설정이 끝났다면 쿼리문이 제대로 동작을 하지는 테스트를 해야합니다. 테스트를 하기위해서 'src/test/java' 경로 안에 TimeMapperTest 클래스 파일을 만들어 다음과 같이 작성하였습니다. 

package com.exe.sample;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.exe.mapper.TimeMapper;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class TimeMapperTests {
	
	@Setter(onMethod_ = @Autowired)
	private TimeMapper timeMapper;
	
	/*
	 * @Test public void testGetTime() { log.info(timemapper.getClass().getName());
	 * log.info(timemapper.getTime2()); }
	 */
	@Test
	public void testGetTime2() {
		log.info("getTime2");
		log.info(timeMapper.getTime2());
	}
}

TimeMapperTests 클래스는 TimeMapper가 정상적으로 동작하는지 테스트하는 역활을 수행하는 파일입니다.

Log4jdbc-log4j2 설정


MyBatis는 내부적으로 JDBC의 PreparedStatement를 이용해서 SQL을 처리합니다. SQL에 전달되는 파라미터는 JDBC에서와 같이 ?로 치환이 되서 처리가 되도록 설계가 되어있습니다. 복잡한 SQL의 경우 ?로 나오는 데이터가 제대로 되어있는지 확인하기가 쉽지 않고 SQL에 있는 내용을 확인하기가 어렵습니다. 이러한 문제를 해결하기 위해서 사용하는 라이브러리가 Log4jdbc-log4j2입니다. 

 

Log4jdbc-log4j2 을 사용하기 위해서 pom.xml 파일에 다음 라이브러리를 설정합니다. 

	<!-- log4jdbc-log4j2-jdbc4 -->
		<dependency>
		    <groupId>org.bgee.log4jdbc-log4j2</groupId>
		    <artifactId>log4jdbc-log4j2-jdbc4</artifactId>
		    <version>1.16</version>
		</dependency>

 

그리고 'src/main/resources'  경로안에 log4jdbc.log4j2.properties 파일을 생성합니다. 

 

 log4jdbc.log4j2.properties 파일

log4jdbc.log4j2.properties 파일을 생성한후 다음 코드를 작성합니다.

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

그리고 root-context.xml 파일을 다음과 같이 수정합니다. 

 

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
		<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"/>
		<property name="jdbcUrl" value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"/>
		<!-- <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:XE"/> -->
		<property name="username" value="cafejun"/>
		<property name="password" value="dkagh1"/>
	</bean>

 

그리고 실행을 했을때 다음 결과가 출력이 되면 log4jdbc가 제대로 적용이 된것입니다. 

 

log4jdbc console 확인 

 

이번 블로그에서는 MyBatis와 스프링 연동에 대해서 살펴보았습니다. 

반응형