Spring - MyBatis

하승·2022년 7월 11일
0

웹 개발반 - Spring

목록 보기
3/8
post-thumbnail

Spring - Mybatis

라이브러리 설정

Spring에 MyBatis를 연동하기 위해서는 pom.xml에 추가적인 라이브러리를 설정해야한다.

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
			<version>8.0.28</version>
		</dependency>

root-context.xml bean 추가

MyBatis에서 가장 핵심적인 객체는 SQLSession과 SQLSessionFactory이다. SQLSessionFactory는 내부적으로 SQLSession을 통해 Connection을 생성하거나 원하는 SQL을 전달하고, 결과를 리턴받는 구조로 작성하게 된다.

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
	</bean>

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

MyBatis 연동

SQL이 짧고 간결한 경우에는 어노테이션을 이용해서 쿼리문을 작성해준다.
SQL이 복잡하거나 길어지는 경우에는 어노테이션보다 XML을 이용하는 것이 좋다.
MyBatis - Spring의 경우 Mapper 인터페이스와 XML을 연동해서 동시에
이용할 수 있다. 인터페이스객체.메소드() 를 호출하는 순간 해당하는 인터페이스의
경로를 namespace로 가지고 있는 XML 파일로 찾아가서 메소드명과 동일한
id를 가지고 있는 쿼리문을 수행하여 결과로 돌려준다.

Mapper 인터페이스

Mapper 패키지를 만든후 TimeMapper 인터페이스를 추가한다.

package com.koreait.mapper;

import org.apache.ibatis.annotations.Select;

public interface TimeMapper {
	//Mapper 인터페이스
	//Mapper를 작성하는 작업은 XMl을 이용할 수도 있지만,
	//최소한의 코드로 작성하기 위해서는 Mapper 인터페이스를 사용한다.
	
	@Select("select now() from dual")
	public String getTime();
	
	public String getTime2();
}

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

<mybatis-spring:scan base-package="com.koreait.mapper"/>

base-package 속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아서 처리한다. 자동으로 com.koreait.mapper 패키지를 인식하는 방식으로 작성되었다.

Mapper 테스트

package com.koreait.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.koreait.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 MapperTests {
	@Setter(onMethod_ = @Autowired)
	private TimeMapper mapper1;
	
	@Test
	public void getTimeTest() {
		log.info("Now : "+mapper1.getTime());
	}


위 코드가 정상적으로 동작한다면 스프링 내부에는 TimeMapper 타입으로 만들어진 스프링 객체(빈)가 존재한다는 뜻이 된다. 즉, 스프링은 인터페이스를 이용해서 객체를 생성한다.


XML 매퍼와 같이 쓰기

XML을 작성해서 사용할 때에는 XML 파일의 위치와 XML 파일에 지정하는 Namespace 속성이 중요하다. 여기서는 ‘src/main/resources’ 폴더 내 패키지로 com.koreait.mapper을 만들어준다.

패키지로 만든다면 폴더가 이런식으로 생성된다. 이후 mapper폴더 안에 TimeMapper.xml을 만들어준다.

Mapper 인터페이스와 XML을 같이 이용해 보기 위해서 기존의 TimeMapper 인터페이스에 추가적인 메서드를 선언한다.

package com.koreait.mapper;

import org.apache.ibatis.annotations.Select;

public interface TimeMapper {
	//Mapper 인터페이스
	//Mapper를 작성하는 작업은 XMl을 이용할 수도 있지만,
	//최소한의 코드로 작성하기 위해서는 Mapper 인터페이스를 사용한다.
	
	@Select("select now() from dual")
	public String getTime();
	
	public String getTime2();
}

메서드를 추가했으면 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에 써준다. -->
<mapper namespace="com.koreait.mapper.TimeMapper">
	<!--	
		id 속성 값은 쿼리를 사용할 때 호출할 메소드의 이름과 동일하게 맞춰야한다.
		resultType 값은 인터페이스에 선언된 메소드의 리턴 타입과 동일하게 작성한다. 
	 -->
	<select id="getTime2" resultType="string">
		select now() from dual
	</select>
</mapper>

XML 매퍼를 이용할 때 신경 써야 하는 부분은 태그의 namespace 속성값이다. MyBatis는 Mapper 인터페이스와 XML을 인터페이스의 이름과 namespace의 속성값을 가지고 판단한다. 위와 같이 namespace에 적힌 값, ‘com.koreait.mapper.TimeMapper’를 알아서 찾아간다.

select 태그의 id 속성 값은 메서드의 이름과 동일하게 작성해야 한다. select 태그의 경우 resultType 속성은 인터페이스에 선언된 메서드의 리턴 타입과 동일하게 작성한다.

테스트

package com.koreait.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.koreait.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 MapperTests {
	@Setter(onMethod_ = @Autowired)
	private TimeMapper mapper1;
 
 	@Test
	public void getTimeTest2() {
		log.info("Now : "+mapper1.getTime2());
	}
 }

테스트 코드를 실행하면 getTime()과 동일한 결과가 출력된다.


log4jdbc-log4j2

MyBatis는 내부적으로 JDBC의 PreparedStatment를 이용해서 SQL을 처리한다.
따라서 SQL에 전달되는 파라미터는 JDBC에서와 같이 ? 로 치환되어서 처리된다.
복잡한 SQL의 경우 ?로 나오는 값이 제대로 전달되었는지 확인하기가 쉽지 않고
실행한 SQL의 내용을 정확히 확인하기 어렵다. 따라서 log4jdbc-log4j2
라이브러리를 사용하여 어떤 값들이 전달되었고, 어떤 쿼리문이 수행되었는지를
확인할 수 있다.

log4jdbc-log4j2 설정

<!-- pom.xml -->
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/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.spylogdelegator.name = net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

log4jdbc를 이용하는 경우에는 JDBC 드라이버와 URL 정보를 수정해야한다.

<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"/>
		<property name="jdbcUrl" value="jdbc:log4jdbc:mysql://localhost:3306/web0315"/>

위의 설정이 제대로 되어 있지 않으면 데이터베이스의 로그가 정상적으로 기록되지 않는다.

설정 변경 후 기존의 테스트 코드를 실행해보면 이전과는 다르게 JDBC와 관련된 로그들이 출력되는 것을 확인할 수 있다.

profile
화이팅!

0개의 댓글