java, spring

[Spring] MyBatis와 스프링 연동하기 1편

isaac.kim 2021. 5. 15. 13:04
728x90
반응형

[Spring] MyBatis와 스프링 연동하기 1편

 

도움이 되셨다면 광고 한 번 클릭 부탁드립니다. 한 번의 클릭이 제게 큰 힘이 된답니다!^^

 

반응형

 

Spring project에 Mybatis를 연동하는 방법에 대해 알아보도록 하겠습니다.

 

스프링 프레임워크와 MyBatis를 연동하면 좀 더 빠르게 SQL을 처리할 수 있는 구조로 만들 수 있고, 많이 사용되는 구조이니 익혀두면 많은 도움이 될 것이라 생각됩니다. 

 

먼저 jdbc, HikariCP 데이터베이스와의 연결에 필요한 라이브러리 및 테스트는 수행이 되어 있어야 Mybatis 연동을 할 수 있습니다. 지난 글에 jdbc와 HikariCP 설정 및 테스트 방법을 올려두었으니, 읽어보시면 도움이 되실 것 같습니다.

 

1. MyBatis

MyBatis는 흔히 SQL 매핑(mapping) 프레임워크로 분류되는데, 개발자들은 JDBC 코드의 복잡하고 지루한 작업을 피하는 용도로 많이 사용합니다. 전통적인 JDBC 프로그래밍의 구조와 비교해보면, MyBatis는 다음과 같은 장점이 있습니다.

 - 자동으로 Connection close() 하는 기능

 - MyBatis 내부적으로 PreparedStatement처리

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

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

 

스프링 프레임워크의 특징 중 하나는 다른 프레임워크들과의 연동을 쉽게 하는 추가적인 라이브러리들이 많다는 것입니다. Mybatis 역시 mybatis-spring이라는 라이브러리를 통해 쉽게 연동할 수 있습니다.

 

2. Mybatis 라이브러리 추가

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

 

라이브러리 추가 목록

- mybatis : mybatis 라이브러리

- mybatis-spring : mybatis와 spring 연동 라이브러리

- spring-tx : spring에서 database처리와 transaction 처리 라이브러리

- spring-jdbc : spring에서 database 처리 라이브러리

 

pom.xml의 dependency에 추가

		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis</artifactId>
		    <version>3.5.6</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<dependency>
		    <groupId>org.mybatis</groupId>
		    <artifactId>mybatis-spring</artifactId>
		    <version>2.0.6</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-tx</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
		<dependency>
		    <groupId>org.springframework</groupId>
		    <artifactId>spring-jdbc</artifactId>
		    <version>${org.springframework-version}</version>
		</dependency>

자신에게 맞는 version을 확인하시는 게 좋습니다.

 

다음과 같은 구조로 mybatis가 사용될 예정입니다.

 

3. SQLSessionFactory 설정

MyBatis에서 가장 핵심 객체는 SQLSession이라는 존재와 SQLSessionFactory입니다.

 

SQLSessionFactory는 내부적으로 SQLSession을 생성하는데, 개발에서는 SQLSession을 통해 Connection을 생성하거나 원하는 SQL을 전달하고, 결과를 리턴 받는 구조로 작성하게 됩니다.

 

root-context.xml 설정

sqlSessionFactory 객체(Bean)을 설정합니다. sqlSessionFactory 설정 이전에 커넥션 풀과 dataSource가 세팅되어 있어야 합니다.

	<!-- HikariCP configuration -->
	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
		destroy-method="close">
		<constructor-arg ref="hikariConfig"/>
	</bean>
    
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

스프링에서 SqlSessionFactory를 등록하는 작업은 SqlSessionFactoryBean을 이용합니다. 패키지명을 보면 MyBatis의 패키지가 아니라 스프링과 연동작업을 처리하는 mybatis-spring 라이브러리의 클래스임을 알 수 있습니다.

 

 

dataSource 및 connection pool 설정이 안 되신 분들은 지난 글을 확인해주세요.

https://lifere.tistory.com/116

 

[Spring] 커넥션 풀(Connection Pool) HikariCP, Java로 설정하기

[Spring] 커넥션 풀(Connection Pool) HikariCP, Java로 설정하기 제 지난 글에서 HikariCP 라이브러리를 root-context.xml 파일로 설정하는 방법에 대해서 다뤘었습니다. 먼저 지난 글을 보시고, 이 글을..

lifere.tistory.com

 

 

4. Java 설정으로 하는 경우, RootConfig 클래스

sqlSessionFactory 를 @Bean을 사용하여 등록합니다.

	@Bean
	public SqlSessionFactory sqlSessionFactory() throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource());
		return (SqlSessionFactory) sqlSessionFactoryBean.getObject();
	}

 

 

5. sqlSessionFactoryBean을 이용하여 SqlSession을 생성하는 테스트

 

TEST코드

기존의 jdbc와 connection pool과 db연결을 확인하기 위해 dataSource도 test를 하고,

sqlSessionFactory의 sqlSession이 생성되는 것을 확인하기 위해 테스트를 진행합니다.

-- 생략 --

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class DataSourceTests {
	
	@Setter(onMethod_ = { @Autowired })
	private DataSource dataSource;
	
	@Setter(onMethod_ = {@Autowired})
	private SqlSessionFactory sqlSessionFactory;
	
	@Test
	public void testMyBatis() {
		try (
			SqlSession session = sqlSessionFactory.openSession();
			Connection con = dataSource.getConnection();
			)
		{
			log.info(session);
			log.info(con);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			fail(e.getMessage());
		}
	}
}

실행결과

위와 같은 결과가 나왔다면 sqlSessionFactory의 기능과 connection pool의 기능이 정상적으로 동작되는 것을 확인할 수 있는 것입니다. 

 

 

6. 스프링과의 연동 처리

SQLSessionFactory를 이용해 코드를 작성해도 직접 Connection을 얻어 JDBC 코딩이 가능하나, 편하게 SQL을 자동으로 처리되는 방식을 사용하는 것이 좋습니다. 이를 위해서는 MyBatis의 Mapper라는 존재를 작성해야 합니다.

 

Mapper는 쉽게 말해 SQL과 그에 대한 처리를 지정하는 역할을 합니다. MyBatis-Spring을 이용하는 경우에는 Mapper을 XML인터페이스 + 어노테이션의 형태로 작성할 수 있습니다.

 

정리하면 Mapper 작성하는 방법 두 가지가 있습니다.

1) Mapper인터페이스 (인터페이스 + 어노테이션)

2) XML Mapper

경험상 두 번째 XML Mapper 방법을 더 많이 사용하는 것을 봐왔습니다. 다음은 두 방법에 대해 알아볼텐데요. 많이 쓰이고 있는 XML Mapper 방식을 사용하실 분은 다음 나오는 내용 중 ★Mapper 설정★ 부분만 참고하시고 XML Mapper를 보시기 바랍니다.

 

 

6.1. Mapper인터페이스 (인터페이스 + 어노테이션)

src/main/java 폴더 밑에 com.project.mapper(원하는 이름으로) 패키지를 만들고, 패키지 안에 TimeMapper라는 인터페이스를 추가합니다.

TimeMapper 인터페이스에는 MyBatis의 어노테이션을 이용해 SQL을 메서드에 추가합니다.

 

※ sql구문은 각 database에 맞게 작성하시면 됩니다. 저는 mysql, mariadb 기준으로 작성했습니다.

> oracle query : SELECT sysdate FROM dual

package com.project.mapper;

import org.apache.ibatis.annotations.Select;

public interface TimeMapper {
	
	@Select("SELECT now()")
	public String getTime();
	
}

 

★Mapper 설정★

Mapper를 작성했다면 MyBatis가 동작할 때 Mapper를 인식할 수 있도록 root-context.xml에 추가적인 설정이 필요합니다. 가장 간단한 방식은 <mybatis:scan>이라는 태그를 이용하는 것입니다.

 

root-context.xml파일을 열고 아래쪽 탭 Namespaces를 선택한 뒤 mybatis-spring에 체크합니다.

그리고 root-context.xml 파일에 다음 scan을 추가합니다.

 

<mybatis-spring:scan> 태그의 base-package 속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아서 처리합니다. Mapper를 설정하는 작업은 각각의 XML이나 Mapper 인터페이스를 설정할 수도 있지만, 매번 너무 번잡하기 때문에 자동으로 com.project.mapper 패키지를 인식하는 방식으로 작성하는 것이 가장 편리합니다.

 

java로 mapper를 scan하는 방식은 다음 @MapperScan을 추가합니다. (root-context.xml을 사용하지 않을 때)

 

Mapper TEST

MyBatis-Spring은 Mapper 인터페이스를 이용해서 실제 SQL 처리가 되는 클래스를 자동으로 생성합니다. 따라서 개발자들은 인터페이스와 SQL만을 작성하는 방식으로도 모든 JDBC 처리를 끝낼 수 있습니다.

 

작성한 TimeMapper를 테스트하는 코드는 src/test/java 밑에 com.project.persistence.TimeMapperTests라는 클래스를 생성해서 처리합니다.

 

TimeMapperTests 클래스

package com.project.persistence;

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.project.mapper.TimeMapper;

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

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
// JAVA 설정의 경우
// @ContextConfiguration(classes = {com.project.config.RootConfig.class})
@Log4j
public class TimeMapperTests {
	
	@Setter(onMethod_ = @Autowired)
	private TimeMapper timeMapper;
	
	@Test
	public void testGetTime() {
		log.info(timeMapper.getClass().getName());
		log.info(timeMapper.getTime());
	}
}

 

 

TimeMapperTests 클래스는 TimeMapper가 정상적으로 사용이 가능한지를 알아보기 위한 테스트 코드입니다. 위 코드가 정상적으로 동작하면 스프링 내부에는 TimeMapper 타입으로 만들어진 스프링 객체(빈)가 존재한다는 뜻이 됩니다.

 

위 코드에서 timeMapper.getClass().getName()은 실제 동작하는 클래스의 이름을 확인해 주는데 실행 결과를 보면 개발 시 인터페이스만 만들어 주었는데 내부적으로 적당한 클래스가 만들어진 것을 확인할 수 있습니다. (AOP에서 볼 내용)

 

우선 여기선 스프링이 인터페이스를 이용해 객체를 생성한다는 사실에 주목합니다.

 

실행결과

정상적으로 SQL이 수행된 것을 확인할 수 있습니다.

 

 

6.2 XML Mapper

MyBatis를 이용해 SQL을 처리할 때 어노테이션을 이용하는 방식이 편리하기는 하지만, SQL이 복잡하거나 길어지는 경우에는 어노테이션 보다는 XML을 이용하는 방식을 더 선호하게 됩니다. 다행히도 MyBatis-Spring의 경우 Mapper 인터페이스와 XML을 동시에 이용할 수 있습니다.

 

XML을 작성해서 사용할 때에는 XML 파일의 위치와 XML 파일에 저장하는 namespace 속성이 중요한데, XML 파일 위치의 경우 Mapper인터페이스가 있는 곳(src/main/java 하위에 com.project.mapper 패키지)에  같이 작성하거나, src/main/resource 구조에 XML을 저장할 폴더를 생성할 수 있습니다. 폴더 밑에 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.project.mapper.TimeMapper">
  
  <select id="getTime2" resultType="string">
    SELECT now()
  </select>
  
</mapper>

XML 매퍼에서 신경 쓸 부분은 <mapper> 태그의 namespace 속성값입니다. MyBatisMapper 인터페이스XML인터페이스의 이름과 namespace 속성을 가지고 판단합니다. 위와 같이 com.proejct.mapper.TimeMapper 인터페이스가 존재하고, XML의 <mapper namespace="com.project.mapper.TimeMapper">와 같이 동일한 이름이 존재하면, 이를 병합해서 처리합니다.

 

병합처리를 확인하기 위해서는 TimeMapper 인터페이스에서 다음 구문 메서드(public String getTime2)를 추가합니다.

위의 경우 메서드 선언은 인터페이스에 존재하고 SQL에 대한 처리는 XML을 이용하는 방식이라고 볼 수 있습니다.

 

위 작성한 xml에서 select 태그의 id가 getTime2로 설정되어 있는 것을 볼 수 있습니다. TimeMapper 인터페이스의 Method의 이름을 getTime2 메서드로 동일하게 맞춥니다. 그리고 이 메서드 위에는 @Select태그나 SQL구문이 존재하지 않습니다.

 

<select> 태그에는 resultType 속성이 있는데 이 값은 인터페이스에 선언된 메서드의 리턴 타입과 동일하게 작성합니다.

 

확인을 위해 TimeMapperTests 클래스에 테스트 코드를 추가해 진행합니다.

테스트 결과

 

getTest2() 테스트 코드의 결과는 getTime()과 같은 역할을 수행하는 것을 확인할 수 있었습니다.

 


정리하면

1. Spring과 MyBatis 연동하기 위한 라이브러리 4개를 다운로드 한다. (pom.xml 설정)

2. Spring과 MyBatis가 SQL연동이 잘 될 수 있도록 SQLSessionFactory 설정

3. Mybatis Mapper를 작성 하되, 두 가지 방법이 존재 / Mapper는 SQL과 그에 대한 처리를 지정하는 역할

 - Mapper 인터페이스

 - Mapper XML 

4. TEST (Junit Test)

 

 

오늘은 MyBatis와 스프링 연동하는 방법에 대해 알아보았습니다!^^


도움이 되셨다면 광고 한 번 클릭 부탁드립니다. 한 번의 클릭이 제게 큰 힘이 된답니다!^^
728x90
반응형