Mapper 인터페이스
Mapper는 쉽게 말해서 SQL과 그에 대한 처리를 지정하는 역할을 합니다. MyBatis-Spring을 이용하는 경우에는 Mapper를 XML과 인터페이스 + 어노테이션의 형태로 작성할 수 있습니다.
Mappper를 작성하는 작업은 XML을 이용할 수도 있지만, 이번 예제에서는 최소한의 코드를 작성하는 Mapper 인터페이스를 사용해 보겠습니다.

TimeMapper 인터페이스에는 MyBatis의 어노테이션을 이용해서 SQL을 메서드에 추가합니다.
▶ TimeMapper 인터페이스
package org.noel.mapper;
import org.apache.ibatis.annotations.Select;
// org.noel.mapper.TimeMapper.getTime2 ->
public interface TimeMapper {
// ; 없어야 한다
@Select("SELECT sysdate From dual")
String getTime();
}
Mapper 설정
Mapper를 작성해 주었다면 MyBatis가 동작할 때 Mapper를 인식할 수 있도록 root-context.xml에 추가적인 설정이 필요합니다. 가장 간단한 방식은 <mybatis:scan>이라는 태그를 이용하는 것입니다.
root-context.xml 파일을 열고, 아래쪽의 'NameSpaces' 항목에서 'mybatis-spring' 탭을 선택합니다.

▶ root-context.xml의 일부
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<mybatis-spring:scan base-package="org.noel.mapper"/>
<context:component-scan base-package="org.noel.sample"></context:component-scan>
<mybatis-spring:scan> 태그의 base-package 속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아서 처리합니다. Mapper를 설정하는 작업은 각각의 XML이나 Mapper 인터페이스를 설정할 수도 있지만, 매번 너무 번잡하기 때문에 예제는 자동으로 org.noel.mapper 패키지를 인식하는 방식으로 작성하는 것이 가장 편리합니다.
Mapper 테스트
MyBatis-Spring은 Mapper 인터페이스를 이용해서 실제SQL 처리가 되는 클래스를 자동으로 생성합니다. 따라서 개발자들은 인터페이스와 SQL만을 작성하는 방식으로 모든 JDBC 처리를 끝낼 수 있습니다.
작성한 TimeMapper를 테스트하는 코드는 src/test/java 밑에 org.noel.persistence.TimeMapperTests라는 클래스를 생성해서 처리합니다.

▶ TimeMapperTests 클래스
package org.noel.persistence;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.noel.mapper.TimeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class TimeMapperTests {
@Autowired
private TimeMapper timeMapper;
@Test
public void testTime1() {
log.info(timeMapper.getTime());
}
}
TimeMapperTests 클래스는 TimeMapper가 정상적으로 사용이 가능한지를 알아보기 위한 테스트 코드입니다. 위의 코드가 정상적으로 동작한다면 스프링 내부에는 TimeMapper 타입으로 만들어진 스프링 객체(빈)가 존재한다는 뜻이 됩니다.
테스트를 실행하면 아래와 같은 로그들이 기록되는 것을 볼 수 있습니다.

XML 매퍼와 같이 쓰기
src/main/resources 폴더 내 다음 그림과 같이 org 폴더 하위에 noel 폴더,mapper 폴더를 작성합니다(한 번에 폴더를 생성하지 말고 한 번에 하나씩 폴더를 생성하기) 생성된 폴더에 TimeMapper.xml 파일을 생성합니다.

XML 파일에는 MyBatis의 XML 매퍼에서 이용하는 태그에 대한 설정이 필요합니다. 이에 대한 자세한 정보는 http://www.mybatis.org/mybatis-3/ko/sqlmap-xml.html를 를 통해서 확인할 수 있습니다.
Mapper 인터페이스와 XML을 같이 이용해 보기 위해서 기존의 TimeMapper 인터페이스에 추가적인 메서드를 선언합니다.

▶ TimeMapper 인터페이스
package org.noel.mapper;
import org.apache.ibatis.annotations.Select;
// org.noel.mapper.TimeMapper.getTime2 ->
public interface TimeMapper {
// ; 없어야 한다
@Select("SELECT sysdate From dual")
String getTime();
String getTime2();
}
TimeMapper 인터페이스를 보면 getTime2()가 추가된 것을 볼 수 있는데 특이하게도 @Select와 같이 MyBatis의 어노테이션이 존재하지 않고 SQL 역시 존재하지 않는 것을볼 수 있습니다.
실제 SQL은 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="org.noel.mapper.TimeMapper">
<select id="getTime2" resultType="string">
SELECT sysdate FROM dual
</select>
</mapper>
XML 매퍼를 이용할 때 신경 써야 하는 부분은 <mapper>태그의 namespace 속성값입니다.
MyBatis는 Mapper 인터페이스와 XML을 인터페이스의 이름과 namespace 속성값을 가지고 판단합니다. 위와 같이 org.noel.mapper.TimeMapper 인터페이스가 존재하고, XML의 <mapper namespace="org.noel.mapper.TimeMapper">같이 동일한 이름이 존재하면, 이를 병합해서 처리합니다. 따라서 위의 경우 메서드 선언은 인터페이스에 존재하고 SQL에 대한 처리는 XML을 이용하는 방식이라고 볼 수 있습니다.
<select> 태그의 id 속성의 값은 메서드의 이름과 동일하게 맞춰야 합니다.때 그의 경우 resultType 속성을 가지는데 이 값은 인터페이스에 선언된 메서드의 리턴 타입과 동일하게 작성합니다.
최종적인 확인을 위해서 TimeMapperTests 클래스를 이용해서 테스트 작업을 진행해야 합니다.
▶ TimeMapperTests 클래스 일부
@Test
public void testGetTime2() {
log.info("getTime2");
log.info(timeMapper.getTime2());
}
getTime2() 테스트 코드의 결과는 gdtTime()과 동일합니다.
log4jdbc-log4j2 설정
MyBatis는 내부적으로 JDBC의 PreparedStatement를 이용해서 SQL을 처리합니다.
따라서 SQL에 전달되는 파라미터는 JDBC에서와 같이 '?'로 치환되어서 처리됩니다. 복잡한SQL의 경우 '?'로 나오는 값이 제대로 되었는지 확인하기가 쉽지 않고 실행된 SQL의 내용을 정확히 확인하기는 어렵습니다.
이런 문제를 해결하기 위해서 SQL을 변환해서 PreparedStatement에 사용된 '?'가 어떤 값으로 처리되었는지 확인하는 기능을 추가하도록 합니다. SQL 로그를 제대로 보기 위해서는 log4jdbc-log4j2
라이브러리를 사용해야 합니다. pom.xml에 라이브러리를 설정합니다.

▶ pom.xml
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
라이브러리를 추가한 후에는 1) 로그 설정 파일을 추가하는 작업과 2) JDBC의 연결 정보를 수정해야 합니다.
우선 src/main/resources 밑에 log4jdbc.log4j2.properties 파일을 추가합니다.

▶ log4jdbc.log4j2.properties
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc를 이용하는 경우는 JDBC 드라이버와 URL 정보를 수정해야 합니다. root-context.xml의 일부를 수정합니다.
▶ root-context.xml의 일부
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<!-- <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"> -->
<!-- </property> -->
<!-- <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:XE"> -->
<!-- </property> -->
<property name="driverClassName"
value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
<property name="jdbcUrl"
value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"></property>
<property name="username" value="book_ex">
</property>
<property name="password" value="noel">
</property>
</bean>
dataSource() 메서드에서 변경되는 부분은 JDBC 드라이버의 클래스를 'net.sf.log4jdbc.sql.jdbcapi.DriverSpy'로 수정하는 작업과 JDBC 연결 URL 부분에서 중간에 'log4jdbc' 문자열이 추가되는 부분입니다. 이 두 설정이 제대로 되어 있지 않으면 데이터베이스의 로그가 정상적으로 기록되지 않습니다.
설정을 변경한 후 기존의 테스트 코드를 실행해보면 이전과는 달리 JDBC와 관련된 로그들이 출력되는 것을 볼 수 있습니다.

'Back-end > Spring Web Project' 카테고리의 다른 글
[Spring Web Project] 스프링 MVC의 Controller(1) - Controller의 파라미터 (1) | 2023.11.21 |
---|---|
[Spring Web Project] 스프링 MVC의 기본 구조 (0) | 2023.11.21 |
MyBatis와 스프링 연동(1) - MyBatis 연동 (0) | 2023.11.14 |
[Spring Web Project] 스프링과 Oracle Database 연동(3) - 커넥션 풀 설정 (0) | 2023.11.13 |
[Spring Web Project] 스프링과 Oracle Database 연동(2) - JDBC 드라이버 연결 확인 (1) | 2023.11.13 |
Mapper 인터페이스
Mapper는 쉽게 말해서 SQL과 그에 대한 처리를 지정하는 역할을 합니다. MyBatis-Spring을 이용하는 경우에는 Mapper를 XML과 인터페이스 + 어노테이션의 형태로 작성할 수 있습니다.
Mappper를 작성하는 작업은 XML을 이용할 수도 있지만, 이번 예제에서는 최소한의 코드를 작성하는 Mapper 인터페이스를 사용해 보겠습니다.

TimeMapper 인터페이스에는 MyBatis의 어노테이션을 이용해서 SQL을 메서드에 추가합니다.
▶ TimeMapper 인터페이스
package org.noel.mapper;
import org.apache.ibatis.annotations.Select;
// org.noel.mapper.TimeMapper.getTime2 ->
public interface TimeMapper {
// ; 없어야 한다
@Select("SELECT sysdate From dual")
String getTime();
}
Mapper 설정
Mapper를 작성해 주었다면 MyBatis가 동작할 때 Mapper를 인식할 수 있도록 root-context.xml에 추가적인 설정이 필요합니다. 가장 간단한 방식은 <mybatis:scan>이라는 태그를 이용하는 것입니다.
root-context.xml 파일을 열고, 아래쪽의 'NameSpaces' 항목에서 'mybatis-spring' 탭을 선택합니다.

▶ root-context.xml의 일부
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<mybatis-spring:scan base-package="org.noel.mapper"/>
<context:component-scan base-package="org.noel.sample"></context:component-scan>
<mybatis-spring:scan> 태그의 base-package 속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아서 처리합니다. Mapper를 설정하는 작업은 각각의 XML이나 Mapper 인터페이스를 설정할 수도 있지만, 매번 너무 번잡하기 때문에 예제는 자동으로 org.noel.mapper 패키지를 인식하는 방식으로 작성하는 것이 가장 편리합니다.
Mapper 테스트
MyBatis-Spring은 Mapper 인터페이스를 이용해서 실제SQL 처리가 되는 클래스를 자동으로 생성합니다. 따라서 개발자들은 인터페이스와 SQL만을 작성하는 방식으로 모든 JDBC 처리를 끝낼 수 있습니다.
작성한 TimeMapper를 테스트하는 코드는 src/test/java 밑에 org.noel.persistence.TimeMapperTests라는 클래스를 생성해서 처리합니다.

▶ TimeMapperTests 클래스
package org.noel.persistence;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.noel.mapper.TimeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class TimeMapperTests {
@Autowired
private TimeMapper timeMapper;
@Test
public void testTime1() {
log.info(timeMapper.getTime());
}
}
TimeMapperTests 클래스는 TimeMapper가 정상적으로 사용이 가능한지를 알아보기 위한 테스트 코드입니다. 위의 코드가 정상적으로 동작한다면 스프링 내부에는 TimeMapper 타입으로 만들어진 스프링 객체(빈)가 존재한다는 뜻이 됩니다.
테스트를 실행하면 아래와 같은 로그들이 기록되는 것을 볼 수 있습니다.

XML 매퍼와 같이 쓰기
src/main/resources 폴더 내 다음 그림과 같이 org 폴더 하위에 noel 폴더,mapper 폴더를 작성합니다(한 번에 폴더를 생성하지 말고 한 번에 하나씩 폴더를 생성하기) 생성된 폴더에 TimeMapper.xml 파일을 생성합니다.

XML 파일에는 MyBatis의 XML 매퍼에서 이용하는 태그에 대한 설정이 필요합니다. 이에 대한 자세한 정보는 http://www.mybatis.org/mybatis-3/ko/sqlmap-xml.html를 를 통해서 확인할 수 있습니다.
Mapper 인터페이스와 XML을 같이 이용해 보기 위해서 기존의 TimeMapper 인터페이스에 추가적인 메서드를 선언합니다.

▶ TimeMapper 인터페이스
package org.noel.mapper;
import org.apache.ibatis.annotations.Select;
// org.noel.mapper.TimeMapper.getTime2 ->
public interface TimeMapper {
// ; 없어야 한다
@Select("SELECT sysdate From dual")
String getTime();
String getTime2();
}
TimeMapper 인터페이스를 보면 getTime2()가 추가된 것을 볼 수 있는데 특이하게도 @Select와 같이 MyBatis의 어노테이션이 존재하지 않고 SQL 역시 존재하지 않는 것을볼 수 있습니다.
실제 SQL은 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="org.noel.mapper.TimeMapper">
<select id="getTime2" resultType="string">
SELECT sysdate FROM dual
</select>
</mapper>
XML 매퍼를 이용할 때 신경 써야 하는 부분은 <mapper>태그의 namespace 속성값입니다.
MyBatis는 Mapper 인터페이스와 XML을 인터페이스의 이름과 namespace 속성값을 가지고 판단합니다. 위와 같이 org.noel.mapper.TimeMapper 인터페이스가 존재하고, XML의 <mapper namespace="org.noel.mapper.TimeMapper">같이 동일한 이름이 존재하면, 이를 병합해서 처리합니다. 따라서 위의 경우 메서드 선언은 인터페이스에 존재하고 SQL에 대한 처리는 XML을 이용하는 방식이라고 볼 수 있습니다.
<select> 태그의 id 속성의 값은 메서드의 이름과 동일하게 맞춰야 합니다.때 그의 경우 resultType 속성을 가지는데 이 값은 인터페이스에 선언된 메서드의 리턴 타입과 동일하게 작성합니다.
최종적인 확인을 위해서 TimeMapperTests 클래스를 이용해서 테스트 작업을 진행해야 합니다.
▶ TimeMapperTests 클래스 일부
@Test
public void testGetTime2() {
log.info("getTime2");
log.info(timeMapper.getTime2());
}
getTime2() 테스트 코드의 결과는 gdtTime()과 동일합니다.
log4jdbc-log4j2 설정
MyBatis는 내부적으로 JDBC의 PreparedStatement를 이용해서 SQL을 처리합니다.
따라서 SQL에 전달되는 파라미터는 JDBC에서와 같이 '?'로 치환되어서 처리됩니다. 복잡한SQL의 경우 '?'로 나오는 값이 제대로 되었는지 확인하기가 쉽지 않고 실행된 SQL의 내용을 정확히 확인하기는 어렵습니다.
이런 문제를 해결하기 위해서 SQL을 변환해서 PreparedStatement에 사용된 '?'가 어떤 값으로 처리되었는지 확인하는 기능을 추가하도록 합니다. SQL 로그를 제대로 보기 위해서는 log4jdbc-log4j2
라이브러리를 사용해야 합니다. pom.xml에 라이브러리를 설정합니다.

▶ pom.xml
<!-- https://mvnrepository.com/artifact/org.bgee.log4jdbc-log4j2/log4jdbc-log4j2-jdbc4.1 -->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
라이브러리를 추가한 후에는 1) 로그 설정 파일을 추가하는 작업과 2) JDBC의 연결 정보를 수정해야 합니다.
우선 src/main/resources 밑에 log4jdbc.log4j2.properties 파일을 추가합니다.

▶ log4jdbc.log4j2.properties
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc를 이용하는 경우는 JDBC 드라이버와 URL 정보를 수정해야 합니다. root-context.xml의 일부를 수정합니다.
▶ root-context.xml의 일부
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<!-- <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"> -->
<!-- </property> -->
<!-- <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:XE"> -->
<!-- </property> -->
<property name="driverClassName"
value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
<property name="jdbcUrl"
value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"></property>
<property name="username" value="book_ex">
</property>
<property name="password" value="noel">
</property>
</bean>
dataSource() 메서드에서 변경되는 부분은 JDBC 드라이버의 클래스를 'net.sf.log4jdbc.sql.jdbcapi.DriverSpy'로 수정하는 작업과 JDBC 연결 URL 부분에서 중간에 'log4jdbc' 문자열이 추가되는 부분입니다. 이 두 설정이 제대로 되어 있지 않으면 데이터베이스의 로그가 정상적으로 기록되지 않습니다.
설정을 변경한 후 기존의 테스트 코드를 실행해보면 이전과는 달리 JDBC와 관련된 로그들이 출력되는 것을 볼 수 있습니다.

'Back-end > Spring Web Project' 카테고리의 다른 글
[Spring Web Project] 스프링 MVC의 Controller(1) - Controller의 파라미터 (1) | 2023.11.21 |
---|---|
[Spring Web Project] 스프링 MVC의 기본 구조 (0) | 2023.11.21 |
MyBatis와 스프링 연동(1) - MyBatis 연동 (0) | 2023.11.14 |
[Spring Web Project] 스프링과 Oracle Database 연동(3) - 커넥션 풀 설정 (0) | 2023.11.13 |
[Spring Web Project] 스프링과 Oracle Database 연동(2) - JDBC 드라이버 연결 확인 (1) | 2023.11.13 |