Spring Boot, MyBatis 연동으로 MySQL 데이터베이스 질의하기

먼저 읽어볼만한 글

데이터베이스 연결 및 질의를 위한 의존성 정보 추가

/build.gradle에 아래 내용을 추가한다. MyBatis 라이브러리를 이용하여 MySQL 데이터베이스에 연결하기 위한 의존성 정보이다.

dependencies {
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc'
    compile group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '1.3.0'
    compile group: 'org.mybatis', name: 'mybatis-typehandlers-jsr310', version: '1.0.2'
    compile group: 'com.ifrabbit', name: 'spring-data-mybatis', version: '1.0.17.RELEASE'
    compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.2'
}
  • mybatis-typehandlers-jsr310 아티팩트는 데이터베이스 컬럼의 날짜/시간 타입을 Java 8부터 추가된 LocalDate, LocalTime, LocalDateTime, Year, Month 클래스로의 자동 맵핑을 지원한다. MyBatis 3.4 버전부터 자동 지원되며 이전 버전은 별도의 typeHandler 등록이 필요하다.

데이터베이스 연결 정보 작성

/src/main/resouces/application.properties에 아래와 같이 연결한 데이터베이스 연결 정보를 작성한다. Profile에 따라 다른 연결 정보를 작성하면 개발, 운영 환경에 따라 연결 데이터베이스를 다르게 설정할 수 있다.

spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_example
spring.datasource.username=root
spring.datasource.password=Q1w2e3r4
spring.datasource.connectionProperties=useSSL=false;useUnicode=yes;characterEncoding=UTF-8;serverTimezone=UTC
spring.datasource.initSQL=SELECT 1

  • DataSourceProperties 클래스에 의해 위에 명시한 데이터베이스 연결 정보를 맵핑한다.


    • spring.datasource.type: 데이터베이스에 연결할 DataSource 클래스명을 명시한다. 여기서는 Tomcat JDBC Connection Pool을 명시했다. 별도로 명시하지 않을 경우 DataSourceBuilder 클래스에 의해 Tomcat JDBC Connection Pool, HikariCP, DBCP 1, DBCP 2 순서대로 유무를 조사하여 자동 등록한다.

    • spring.datasource.driverClassName: 데이터베이스에 연결할 Driver 클래스명을 명시한다. MySQL에 접속하기 위해 Connector/J를 명시했다. 역시 별도로 명시하지 않을 경우 자동 등록한다.


  • Tomcat JDBC Connection Pool을 사용할 경우 PoolConfiguration 클래스에 의해 추가 설정을 적용한다. 위 예제에는 2개의 추가 설정 만을 명시했지만 실제로 레퍼런스 문서에 명시된 모든 설정 값을 명시할 수 있다.


    • spring.datasource.connectionProperties: 데이터베이스 연결시 적용할 파라메터를 명시한다. 데이터베이스 환경마다 다르므로 적절한 파라메터를 입력한다.


    • spring.datasource.initSQL: 새로운 연결을 생성할 때 마다 실행할 SQL 문을 명시한다.


  • DataSourceAutoConfiguration 클래스에 의해 위 맵핑된 데이터베이스 연결 정보로 dataSource(javax.sql.DataSource) 이름의 빈을 생성한다. 위 방법을 사용하지 않고 직접 입맛에 맞게 dataSource 빈을 생성해도 무방하다.


  • MybatisAutoConfiguration 클래스에 의해 위 생성된 dataSource 빈을 자동으로 인지하여 sqlSeesionFactory(org.mybatis.spring), sqlSessionTemplate(org.mybatis.spring) 이름의 빈을 생성한다. 이 것 만으로 애플리케이션에서 MySQL 데이터베이스에 질의하기 위한 준비는 끝났다.

데이터베이스 질의를 수행하는 DAO 클래스 작성

/src/main/com.jsonobject.example/ExampleDAO.java를 아래와 같이 작성한다. 데이터베이스의 현재 시간을 문자열로 반환하는 간단한 기능이다. 아래와 같은 어노테이션 기반의 질의문 작성은 간단하고 직관적이지만 실제로 프로덕션 레벨에서 요구되는 Dynamic SQL을 소화하기에는 한계가 있으므로 XML 방식의 Mapper 사용을 추천한다.

package com.jsonobject.example;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface ExampleDAO {

    @Select("SELECT NOW()")
    String getCurrentDateTime();
}

DAO를 소비하는 비즈니스 로직 작성

아래는 앞서 작성한 DAO 클래스를 이용하여 비즈니스 로직을 작성한 예이다. 기본적인 Java, JDBC를 이용한 질의에 비해 Spring Boot, MyBatis를 이용한 질의는 매우 간단한 것을 확인할 수 있다.

package com.jsonobject.example;

@Service
public class ExampleService {

    @Autowired
    private ExampleDAO exampleDAO;

    public String getCurrentDataTime() {

        return exampleDAO.getCurrentDateTime();
    }
}

2개 이상의 데이터베이스 연결을 위한 설정

앞서 설명한 방법은 애플리케이션에서 1개의 데이터베이스에만 연결한다는 전제 하에 Spring Boot, MyBatis에 의해 미리 만들어진 코드에 의해 각 1개의 DataSource, SqlSessionFactory, SqlSessionTemplate 빈을 자동으로 생성하고 사용하는 시나리오였다. 하지만 프로덕션 레벨에서는 2개 이상의 데이터베이스에 연결하는 요구사항이 흔히 발생한다. 이번에는 2개 이상의 데이터베이스 질의를 수용할 수 있는 방법을 설명한다. 연결할 데이터베이스의 이름을 first라고 가정하고 진행하겠다.

/src/main/resources/application.properties 파일을 아래와 같이 작성한다.

spring.first.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.first.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.first.datasource.url=jdbc:mysql://localhost:3306/spring_boot_example
spring.first.datasource.username=root
spring.first.datasource.password=Q1w2e3r4
spring.first.datasource.connectionProperties=useSSL=false;useUnicode=yes;characterEncoding=UTF-8;serverTimezone=UTC
spring.first.datasource.initSQL=SELECT 1
  • first라는 키워드를 부여함으로서 추후 second, third 등 2개 이상의 데이터베이스 연결이 가능하도록 확장성을 부여했다. 단지 예시일 뿐 어떤 이름을 부여해도 무방하다.

/src/main/java/com.jsonobject.example/FirstDataSoureConfig.java 파일을 아래와 같이 작성한다.

package com.jsonobject.example;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class FirstDataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.first.datasource")
    public DataSource firstDataSource() {

        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory firstSqlSessionFactory(DataSource firstDataSource, ApplicationContext applicationContext) throws Exception {

        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(firstDataSource);
        sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mapper/first/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate firstSqlSessionTemplate(SqlSessionFactory firstSqlSessionFactory) throws Exception {

        return new SqlSessionTemplate(firstSqlSessionFactory);
    }
}
  • 앞서 1개의 데이터베이스 만을 구성할 때는 별도의 클래스 작성이 필요 없었지만 2개 이상부터는 위와 같이 DataSource, SqlSessionFactory, SqlSessionTemplate 빈을 별도로 생성하는 작업이 필요하다. 다른 데이터베이스 연결을 위한 작업시 위와 동일한 형태의 클래스를 작성해주면 된다.

/src/main/java/com.jsonobject.example/ExampleDAO.java 파일을 아래와 같이 작성한다.

package com.jsonobject.example;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

@Repository
public class ExampleDAO {

    @Autowired
    @Qualifier("firstSqlSessionTemplate")
    private SqlSession sqlSession;

    public String getCurrentDateTime() {

        return sqlSession.selectOne("com.jsonobject.example.mapper.ExampleMapper.getCurrentDateTime");
    }
}
  • 앞서 생성한 firstSqlSessionTemplate 빈을 맵핑한 것을 확인할 수 있다.

마지막으로 /src/main/resources/mapper/first/ExampleMapper.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.jsonobject.example.mapper.ExampleMapper">
    <select id="getCurrentDateTime" resultType="String">
        SELECT NOW()
    </select>
</mapper>
  • MyBatis의 장기인 강력한 Dynamic SQL 기능을 이용하려면 위와 같이 Mapper라 불리는 XML 문서에 SQL 문을 작성해야 한다. 프로젝트의 통일성을 위해 DAO 클래스의 패키지명과 일치하는 경로에 저장하도록 한다. 예를 들면 아래와 같다.
    • /src/main/java/com/jsonobject/example/dao/UserDAO.java
    • /src/main/resources/com/jsonobject/example/mapper/UserMapper.xml

레플리케이션 연결을 위한 설정

레플리케이션 구성은 아래 글을 참고한다.

참고 글


저작자 표시 비영리 동일 조건 변경 허락
신고