MyBatis와 스프링 연동
연동에 앞서 MyBatis란?
- SQL Mapping 프레임 워크
SQL과 Object 간의 관계를 매핑해주는 역할
JDBC 코드에 비해 처리하는 부분이 간결해지고, close 처리를 지원
※ JPA와는 다름. JPA(RDBMS -> 객체지향에 접목). MyBatis는 SQL, 객체지향 매핑하는 역할 - Spring에서의 사용
스프링은 MyBatis와의 연결을 위한 mybatis-spring 라이브러리를 이용해서 연동 처리
MyBatis 세팅
기본적으로 dataSource 설정 필요
pom.xml 라이브러리 추가
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
위의 라이브러리만 추가해도 개발이 가능하지만, 스프링과 연동하면 더 좋아짐. MyBatis Spring 라이브러리도 추가
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
추가적인 설정이 필요 spring-jdbc, spring-tx
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework-version}</version>
</dependency>
SqlSeesionFactory의설정
root-context.xml에 MyBatis설정
MyBatis의 핵심 객체는 SqlSessionFactory 타입의 객체
SqlSessionFactoryBean은 내부적으로 MyBatis의 SqlSessionFactory를 생성
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dateSource"></property>
</bean>
동작 확인(매우 중요한 설정이므로 하나씩 확인-동작해주는 것을 추천)
DataSourceTests에 아래 코드를 추가
package org.zerock.persistence;
(...생략...)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class DataSourceTests {
(...생략...)
@Autowired
private SqlSessionFactory sqlSessionFactory;
(...생략...)
@Test
public void testConnection2() {
try (SqlSession session = sqlSessionFactory.openSession(); Connection connection = session.getConnection()) {
log.info(session);
log.info(connection);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
}
AutoClose하기 때문에 close를 해주지 않아도 됨
스프링 연동 처리 및 연동 테스트
src/main/java 폴더 안에 org.zerock.mapper 패키지를 생성 → TimeMapper 인터페이스
package org.zerock.mapper;
import org.apache.ibatis.annotations.Select;
public interface TimeMapper {
@Select("select sysdate from dual") // 주의 ;(세미콜론)이 없어야함
public String getTime();
}
Mapper 설정 root-context.xml에서 Namespaces에서 Mybatis-spring을 체크
체크하고 Source를 확인하면 코드가 자동으로 추가됨
자동 완성 기능이 됨
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="hikariConnfig" 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="username" value="book_ex"></property>
<property name="password" value="book_ex"></property>
</bean>
<bean id="dateSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConnfig" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dateSource"></property>
</bean>
<mybatis-spring:scan base-package="org.zerock.mapper"/>
<context:component-scan base-package="org.zerock.sample"></context:component-scan>
</beans>
이 과정까지하면 연동 처리가 완료
테스트 진행
src/test/java 폴더의 org.zerock.persistence 패키지 안에 TimeMapperTests클래스를 생성
package org.zerock.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 org.zerock.mapper.TimeMapper;
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() {
timeMapper.getTime(); // 호출
}
}
package org.zerock.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 org.zerock.mapper.TimeMapper;
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() {
// timeMapper.getTime(); // 호출
log.info(timeMapper.getTime());
}
}
XML Mapper 설정
spring-test를 이용해서 테스트 코드 작성 시 sql이 길어지면 관리가 힘들어짐. XML Mapper와 Mapper 인터페이스를 사용
XML 파일은 src/main/java 폴더 mapper 패키지에 생성하거나 src/main/resources 폴더에 mapper 폴더를 만들고 생성해도 됨
단, src/main/resources 폴더에 만들때 폴더를 만들 때 하나하나씩 만들어야함
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">
↑ XML 문서를 만들면 dtd -> 자동완성기능
위의 코드를 작성하면 자동완성기능이 되며, 아래와 같이 쿼리를 작성
<?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.zerock.mapper.TimeMapper"> <!-- namespace는 인터페이스와 동일하게 -->
<select id="getTime2"> <!-- getTime2에는 sql이 없음 -> mybatis는 xml에서 찾아 sql을 실행 -->
select sysdate from dual
</select>
</mapper>
현재 동작 확인
TimeMapperTests에 코드 추가
@Test
public void testTime2() {
log.info(timeMapper.getTime2());
}
sql은 실행되었으나 처리를 어떻게 해야할지 모르겠다는 의미의 에러가 발생
select의 경우 반환타입이 있어야함
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.zerock.mapper.TimeMapper">
<select id="getTime2" resultType="string"> <!-- getTime2에는 sql이 없음 -> mybatis는 xml에서 찾아 sql을 실행 -->
select sysdate from dual
</select>
</mapper>
정상 동작
mybatis 연동, spring-mybatis연동, xml처리까지 완료
log4jdbc-log4j2 설정
※ MyBatis는 내부적으로 PreparedStatement를 이용하기 때문에 좀 더 쉽게 SQL의 로그를 보기 위한 설정 → DB 버전에 조심해야함. 안될 경우 순수 jdbc로 로그를 찍어야함
순서 : 라이브러리 추가 → 프로퍼티 파일 추가 → DataSource 설정 변경
라이브러리 추가
<!-- 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>
프로퍼티 파일을 반드시 추가
이 파일을 src/main/resources에 추가 테스트할 때 불안해서 저자는 src/test/resources에도 함께 추가하는 것을 추천함
DataSource 설정 변경
root-context.xml에서
<bean id="hikariConnfig" 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="username" value="book_ex"></property>
<property name="password" value="book_ex"></property>
</bean>
이 부분을 수정
<bean id="hikariConnfig" class="com.zaxxer.hikari.HikariConfig">
<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="book_ex"></property>
</bean>
이 상태에서 JUnit 테스트
콘솔창 내용을 복사 붙여넣기
|----------------------|
|sysdate |
|----------------------|
|2024-12-29 15:31:58.0 |
|----------------------|
INFO : jdbc.resultset - 1. ResultSet.next() returned false
INFO : jdbc.resultset - 1. ResultSet.close() returned void
INFO : jdbc.audit - 1. Connection.getMetaData() returned oracle.jdbc.driver.OracleDatabaseMetaData@5b12012e
INFO : jdbc.audit - 1. PreparedStatement.close() returned
INFO : jdbc.audit - 1. Connection.clearWarnings() returned
INFO : org.zerock.persistence.TimeMapperTests - 2024-12-29 15:31:58.0
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
INFO : jdbc.connection - 1. Connection closed
INFO : jdbc.audit - 1. Connection.close() returned
INFO : jdbc.connection - 2. Connection closed
INFO : jdbc.audit - 2. Connection.close() returned
INFO : jdbc.connection - 3. Connection closed
INFO : jdbc.audit - 3. Connection.close() returned
INFO : jdbc.connection - 4. Connection closed
INFO : jdbc.audit - 4. Connection.close() returned
INFO : jdbc.connection - 5. Connection closed
INFO : jdbc.audit - 5. Connection.close() returned
INFO : jdbc.connection - 6. Connection closed
INFO : jdbc.audit - 6. Connection.close() returned
INFO : jdbc.connection - 7. Connection closed
INFO : jdbc.audit - 7. Connection.close() returned
INFO : jdbc.connection - 8. Connection closed
INFO : jdbc.audit - 8. Connection.close() returned
INFO : jdbc.connection - 9. Connection closed
INFO : jdbc.audit - 9. Connection.close() returned
INFO : jdbc.connection - 10. Connection closed
INFO : jdbc.audit - 10. Connection.close() returned
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
이렇게 동작하지 않는다면
설정 전 동작하는지 확인하고 동작 확인이 되는데 안된다면 DB나 JDBC 드라이버의 지원이 안됨.
'organize > 스프링' 카테고리의 다른 글
스프링 웹 프로젝트 5 (0) | 2024.12.31 |
---|---|
스프링 웹 프로젝트 4 (0) | 2024.12.30 |
스프링 웹 프로젝트 2 (0) | 2024.12.28 |
스프링 웹 프로젝트 1 (3) | 2024.12.27 |
웹 시큐리티 (0) | 2024.10.05 |