본문 바로가기
Spring Boot

스프링 부트(Spring Boot) - 게시판 MariaDB(HikariCP) 연동하기 [Thymeleaf, MariaDB, IntelliJ, Gradle, MyBatis]

by 도뎡 2023. 3. 20.
반응형
  • 본 게시판 프로젝트는 단계별(step by step)로 진행되니, 이전 단계를 진행하시는 것을 권장드립니다.
  • 본 포스팅은 DBeaver를 기준으로 작성된 글이며, 만약 MariaDB가 설치되어 있지 않으시다면, 선행 작업
     MariaDB 설치하기를 꼭! 진행해 주세요.

이전 글에서는 스프링 부트 프로젝트의 구조와 필수적인 파일, 그리고 MVC 패턴에 대해 알아보았습니다. 이번에는 스프링 부트와 MariaDB 데이터베이스를 연동하는 시간을 가져보도록 할 건데요. PC에 MariaDBGUI 툴이 설치되어 있다는 가정 하에 진행합니다.

 

GUI 툴은 본인에게 가장 익숙한 걸 사용하시는 게 좋습니다. 저는 DBeaver라는 툴을 사용하고 있는데, 여러 DBMS를 지원해 주기도 하고, 이클립스와 단축키가 거의 동일하기 때문에 개인적으로 정말 편리하고 유용한 툴이라고 생각합니다.

 

 

1. DB 커넥션 생성하기


1-1) Database Navigator 영역에서 마우스를 우클릭한 후

Create - Connection을 클릭해 주세요.

DB 커넥션 생성 1

 

 

 

1-2) DB 선택 창이 열리면, MariaDB를 선택하고 다음을 클릭해 주세요.

DB 커넥션 생성 2

 

 

 

1-3) 이제 DB 접속 정보를 입력해 주시면 되는데요.

좌측 하단의 Test Connection을 통해

DB와 정상적으로 연결되었는지 확인할 수 있습니다.

 

(만약 드라이버 파일 다운로드 창이 열린다면, 다운로드해 주시면 됩니다!)

DB 커넥션 생성 3

 

파라미터 설명
Server Host 데이터베이스를 연결할 주소를 의미합니다. 우리는 자신의 컴퓨터를 의미하는 로컬 호스트(localhost)에서 개발하며, 주소는 localhost 또는 127.0.0.1을 입력해야 합니다.
Port MariaDB의 기본 포트 번호는 MySQL과 마찬가지로 3306입니다.
Username 데이터베이스의 마스터 계정인 root 계정을 입력합니다.
Password MariaDB를 설치하는 과정에서 입력했던 패스워드를 입력합니다.
Database 커넥션에서 기본으로 사용할 스키마(Schema)를 의미합니다. 아직은 스키마를 생성하지 않았으니 우선은 비워두도록 하겠습니다.

 

 

 

1-4) 접속에 성공했다면 다음과 같은 화면을 보실 수 있습니다.

알림 창을 닫고, 하단의 완료 버튼을 클릭해 주세요.

커넥션 테스트 실행 결과

 

 

 

1-5) Database Navigator 영역에서 생성된 커넥션 정보를 확인하실 수 있으며,

커넥션 선택 후 F2를 누르면 커넥션 이름을 변경할 수 있습니다.

커넥션 생성 완료


 

2. 스키마(Schema) 생성하기

이제 생성된 커넥션에 접속해서 스키마를 생성할 건데요. 스키마는 데이터베이스상의 작업 공간(workspace)으로 볼 수 있으며, 쉽게 (Schema == Database)로 이해해 주시면 됩니다. 스키마는 이하 DB로 칭하도록 하겠습니다.


2-1) Databases 영역에서 마우스를 우클릭한 후

Create New Database를 클릭해 주세요.

DB 생성 1

 

 

 

2-2) DB 이름은 개발환경 설정하기에서 생성한 게시판 프로젝트명과 동일하게 board로,

Charset과 Collation은 디폴트 옵션인 utf8mb4 그대로 두시면 됩니다.

DB 생성 2

 

 

 

2-3) 생성된 board DB는 다음과 같은 구조로 이루어져 있습니다.

우리는 앞으로 board DB의 Tables에 게시판 프로젝트에 필요한 테이블들을 생성하게 됩니다. 

DB 생성 완료


 

 

3. 기본 DB(Default Database) 지정하기

다음의 이미지는 SQL 편집기에서 "SHOW DATABASES" 명령어를 실행한 결과입니다. 편집기를 여는 방법은 뒤에서 말씀드리도록 하겠습니다.

SHOW DATABASES 명령어 실행 결과

 

 

 

우리는 지금부터 모든 SQL 쿼리를 board DB를 기준으로 실행하게 되는데요. 커넥션 내에서 사용할 DB를 지정하려면, (1) SQL 편집기에서 "USE DB명" 명령어를 실행하거나, (2) 커넥션에서 기본 DB를 지정해 주어야 합니다.

 

하지만, 1번과 같이 커넥션을 맺을 때마다 명령어를 실행한다는 건 매우 귀찮은 일이니, 우리는 커넥션을 맺는 시점에 기본적으로 board DB를 바라볼 수 있도록 커넥션 정보를 수정해 주도록 하겠습니다.


3-1) 커넥션에서 마우스를 우클릭한 후 Edit Connection을 클릭해 주세요.

기본 DB 설정 1

 

 

 

3-2) Database에 board를 입력하고 Test Connection을 클릭해 주세요.

정상적으로 연결되었다면, 앞에서와 마찬가지로 커넥션 성공 메시지를 보실 수 있습니다.

기본 DB 설정 2

 

 

 

3-3) 리커넥트 컨펌(Confirm) 창이 열리면 '예'를 클릭해서 수정을 완료해 주세요.

기본 DB 설정 3

 

 

 

3-4) 커넥션에서 마우스를 우클릭한 후 SQL 편집기를 열어주세요.

(커넥션을 선택(클릭) 한 후 F3을 누르셔도 됩니다!)

SQL 편집기 오픈 방법

 

 

 

3-5) MariaDB에서 "SHOW TABLES" 명령어를 실행하면

DB에 있는 모든 테이블을 조회할 수 있습니다.

 

아직은 어떤 테이블도 생성하지 않았으니 조회 결과가 없는 게 정상입니다.

유용하게 사용되는 명령어이니 꼭! 기억해 주세요.

SHOW TABLES 명령어 실행 결과


 

4. 데이터 소스(DataSource) 설정하기

데이터 소스는 DB와의 커넥션을 관리해 주는 인터페이스입니다. 데이터 소스의 정의는 뒤에서 자세히 설명드리도록 하겠습니다.

 

데이터 소스 설정은 대표적으로 두 가지 방법을 이용할 수 있습니다.

  • application.properties에 DB 정보를 선언해 두고, 설정(Configuration) 파일에서 참조하는 방법
  • 설정(Configuration) 파일에서 DB 정보를 직접 입력하는 방법

 

우리는 이 중 첫 번째 방법을 이용해 데이터 소스 빈(Bean)을 구성합니다. 우선, src/main/resources 디렉터리의 application.properties에 다음의 코드를 작성해 주세요.

spring.datasource.hikari.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mariadb://localhost:3306/board?serverTimezone=Asia/Seoul&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.hikari.username=username
spring.datasource.hikari.password=password
spring.datasource.hikari.connection-test-query=SELECT NOW() FROM dual

 

속성 설명
jdbc-url 데이터베이스의 주소를 의미합니다. 포트 번호(3306) 뒤의 board는 애플리케이션에서 참조할 DB의 이름이며, serverTimezone 등의 파라미터는 시간, 한글 처리 등 기본적인 설정을 처리하는 용도의 파라미터입니다.
username DB의 계정 아이디를 의미합니다. 별개로 추가한 사용자가 없다면, 마스터 계정인 root를 입력해 주시면 됩니다.
password username에 입력한 사용자의 비밀번호를 의미합니다. 별개로 추가한 사용자가 없다면, root 계정의 비밀번호를 입력해 주시면 됩니다.
connection-test-query 커넥션이 정상적으로 맺어졌는지 확인하기 위한 SQL 쿼리입니다. 애플리케이션이 실행되면 다음의 테스트 쿼리가 콘솔에 출력됩니다. 참고로, 아직은 애플리케이션이 실행되지 않는 것이 정상입니다.

 

5. 데이터 소스 설정(Data Source Configuration) 클래스 추가하기

스프링 레거시는 일반적으로 XML 설정 파일에 데이터 소스를 구성합니다. 이전에 말씀드렸듯이 스프링 부트는 클래스 선언부에 @Configuration 어노테이션만 선언해 주면, 해당 파일이 Java 기반의 설정 파일임을 인식합니다.

 

우리는 Java 기반의 설정을 이용하기로 했으니, 데이터 소스 객체(Bean)를 관리해 줄 설정(Configuration) 클래스가 필요합니다.


5-1) 패키지, 클래스 추가하기

src/main/java 디렉터리의 com.study 패키지에 config 패키지를 추가하고, 그 안에 DatabaseConfig 클래스를 추가해 주세요. 결과적으로 다음과 같은 구조가 되어야 합니다.

 

패키지와 클래스가 추가된 디렉터리 구조

 

 

 

5-2) 소스 코드 작성하기

DatabaseConfig에 아래 소스 코드를 작성해 주시면 되는데요. 주석 처리된 부분은 나중에 SQL 쿼리를 작성하는 과정에서 설명드리도록 하겠습니다.

 

혹시라도 에러가 발생한다면 import 부분을 다시 한번 확인해 주세요.


<TIP> IDE의 자바(Java) 파일에서 Ctrl + Shift + O를 누르면, 자동 import가 가능합니다.


package com.study.config;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfig {

    @Autowired
    private ApplicationContext context;

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariConfig hikariConfig() {
        return new HikariConfig();
    }

    @Bean
    public DataSource dataSource() {
        return new HikariDataSource(hikariConfig());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());
//		factoryBean.setMapperLocations(context.getResources("classpath:/mappers/**/*Mapper.xml"));
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSession() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

}

 

어노테이션 설명
@Configuration 스프링은 @Configuration이 선언된 클래스를 자바(Java) 기반의 설정 파일로 인식합니다. 스프링 레거시의 XML 설정 방식을 Java 클래스로 대체한 것으로 생각해 주시면 되겠습니다.
@PropertySource 해당 클래스에서 참조할 properties의 경로를 선언(지정)합니다.
@Autowired 빈(Bean)으로 등록된 인스턴스(이하 객체)를 클래스에 주입하는 데 사용합니다. @Autowired 이외에도 @Resource, @Inject 등이 존재합니다.

나중에는 롬복(Lombok)이라는 라이브러리를 이용해 스프링에서 권장하는 생성자 주입 방식을 이용합니다.
ApplicationContext 스프링 컨테이너(Spring Container) 중 하나입니다. 컨테이너는 사전적 의미로 무언가를 담는 용기 또는 그릇을 의미하는데요. 스프링 컨테이너는 빈(Bean)의 생성과 사용, 관계, 생명 주기 등을 관리합니다.

빈(Bean)은 쉽게 말해 Java 객체입니다. 예를 들어, 프로젝트에 100개의 클래스가 있다고 가정해 보겠습니다. 이 클래스들이 서로에 대한 의존성이 높다고 했을 때 "결합도가 높다."라고 표현하는데, 이러한 문제를 컨테이너에서 빈(Bean)을 주입받는 방법으로 해결할 수 있습니다. 즉, 클래스간의 의존성을 낮출 수 있는 것입니다.

주입받는 방법은 뒤에서 테스트를 진행하며 알아보도록 하겠습니다.
@Bean Configuration 클래스의 메서드 레벨에만 선언이 가능하며, @Bean이 선언된 객체는 스프링 컨테이너에 의해 관리되는 빈(Bean)으로 등록됩니다.

해당 어노테이션은 인자로 몇 가지 속성(옵션)을 지정할 수 있으며,
마찬가지로 테스트를 진행하며 알아보도록 하겠습니다.
@ConfigurationProperties 해당 어노테이션은 인자에 prefix 속성을 선언(지정)할 수 있는데요. prefix는 접두사, 즉 머리를 의미합니다.

우리는 prefix에 spring.datasource.hikari를 선언했습니다. 쉽게 말해 @PropertySource에 선언된 파일(application.properties)에서 prefix에 해당하는 spring.datasource.hikari로 시작하는 설정을 모두 읽어 들여 해당 메서드에 매핑(바인딩)하는 개념입니다.

추가적으로 해당 어노테이션은 메서드뿐만 아니라 클래스 레벨에도 선언할 수 있습니다.
hikariConfig 히카리CP 객체를 생성합니다. 히카리CP는 커넥션 풀(Connection Pool) 라이브러리 중 하나이며, 아래의 데이터 소스와 함께 알아보도록 하겠습니다.
dataSource 데이터 소스 객체를 생성합니다. 순수 JDBC는 SQL을 실행할 때마다 커넥션을 맺고 끊는 I/O 작업을 하는데, 이 작업은 상당한 양의 리소스를 잡아먹는다고 합니다. 그리고, 이 문제의 해결책으로 커넥션 풀이 등장했습니다.

커넥션 풀은 커넥션 객체를 생성해두고, DB에 접근하는 사용자에게 미리 생성해둔 커넥션을 제공했다가 다시 돌려받는 방법입니다.

데이터 소스는 커넥션 풀을 지원하기 위한 인터페이스입니다.
sqlSessionFactory SqlSessionFactory 객체를 생성합니다. SqlSessionFactory는 DB 커넥션과 SQL 실행에 대한 모든 것을 갖는 객체입니다.

SqlSessionFactoryBean은 FactoryBean 인터페이스의 구현 클래스로, 마이바티스(MyBatis)와 스프링의 연동 모듈로 사용됩니다.

쉽게 말해 factoryBean 객체는 데이터 소스를 참조하며, XML Mapper(SQL 쿼리 작성 파일)의 경로와 설정 파일 경로 등의 정보를 갖는 객체입니다.
sqlSession
sqlSession 객체를 생성합니다. 마이바티스 공식 문서에는 다음과 같이 정의되어 있습니다.

1. SqlSessionTemplate은 마이바티스 스프링 연동 모듈의 핵심이다.
2. SqlSessionTemplate은 SqlSession을 구현하고, 코드에서 SqlSession을 대체한다.
3. SqlSessionTemplate은 쓰레드에 안전하고, 여러 개의 DAO나 Mapper에서 공유할 수 있다.
4. 필요한 시점에 세션을 닫고, 커밋 또는 롤백하는 것을 포함한 세션의 생명주기를 관리한다.

(뭐라는 거야...)

SqlSessionTemplate은 SqlSessionFactory를 통해 생성되고, 공식 문서의 내용과 같이 DB의 커밋, 롤백 등 SQL의 실행에 필요한 모든 메서드를 갖는 객체로 생각할 수 있는데요. SQL 쿼리를 작성하는 과정에서 자세히 알아보도록 하겠습니다.

 

6. JUnit으로 단위 테스트 해보기

스프링은 단위 테스트를 위한 환경과 다양한 기능들을 아낌없이 제공해주고 있습니다. 일반적으로 단위 테스트는 비즈니스 로직 또는 SQL 쿼리에 문제가 있는지 확인하는 용도로 사용되는데요. WAS(톰캣)를 구동하지 않은 상태에서도 테스트가 가능하기 때문에 시간적인 측면에서 상당히 유리합니다.


6-1) 소스 코드 작성하기

여기서는 DatabaseConfig 클래스에 구성한 빈(Bean)을 기준으로 JUnit 단위 테스트 방법을 설명드리도록 하겠습니다. src/test/java 디렉터리의 BoardApplicationTests에 다음의 코드를 작성해 주세요.

package com.study;

import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

@SpringBootTest
class BoardApplicationTests {

    @Autowired
    private ApplicationContext context;

    @Autowired
    private SqlSessionFactory sessionFactory;

    @Test
    void contextLoads() {
    }

    @Test
    public void testByApplicationContext() {
        try {
            System.out.println("=========================");
            System.out.println(context.getBean("sqlSessionFactory"));
            System.out.println("=========================");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testBySqlSessionFactory() {
        try {
            System.out.println("=========================");
            System.out.println(sessionFactory.toString());
            System.out.println("=========================");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

 

 

6-2) 테스트 코드 실행하기

클래스에서 메서드 이름을 더블 클릭하면 블록이 잡히게 되는데요. 이 상태에서 마우스를 우클릭한 후 "Run... Test" 또는 "Debug... Test"를 실행해 주시면 됩니다. 메서드의 실행 결과는 IDE 콘솔에서 확인할 수 있습니다.

테스트 코드 실행 방법

 

 

6-3) 테스트 코드 실행하기 1

다음은 testByApplicationContext( )의 단위 테스트 실행 결과입니다. 콘솔에 SqlSessionFactory 객체의 주소 값이 출력되었다면 테스트에 성공한 것입니다.

testByApplicationContext( ) 단위 테스트 실행 결과

 

 

실행한 테스트 코드에서는 context 객체의 getBean( ) 메서드에 "sqlSessionFactory"를 전달했습니다. 여기서 context는 스프링 컨테이너 중 하나인 ApplicationContext의 객체이며, 스프링 컨테이너는 빈(Bean)의 생명 주기를 관리한다는 말씀을 드렸습니다.

 

즉, 스프링 컨테이너에 담겨있는 SqlSessionFactory 빈(Bean)을 꺼내오는 개념으로 이해해 주시면 되는데요.  getBean( ) 메서드의 인자로 전달한 문자열이 SqlSessionFactory 빈(Bean)의 메서드명이라는 것이 포인트입니다.

SqlSessionFactory 빈(Bean) 이름

 

 

6-4) 테스트 코드 실행하기 2

다음은 testBySqlSessionFactory( )의 단위 테스트 실행 결과입니다. 6-3의 테스트 코드와 마찬가지로 객체의 주소 값이 콘솔에 출력됩니다.

testBySqlSessionFactory( ) 단위 테스트 실행 결과

 

앞의 두 테스트 코드 모두 SqlSessionFactory 타입의 객체입니다. 여러분은 "컨테이너에서 빈(Bean)을 이런 식으로 주입해 주는구나!" 정도만 기억해 주시면 되겠습니다.

 

 

 

6-5) 빈(Bean) 이름 변경해 보기

마지막으로 @Bean 어노테이션의 name 속성을 이용해서 객체를 주입받는 방법입니다. 다음은 SqlSessionFactory 빈(Bean)의 이름을 "abc"로 변경해서 단위 테스트를 실행한 결과입니다.

빈(Bean) name 선언 방법

 

 

 

testByApplicationContext( ) 단위 테스트 실행 결과

 

 

 

여기에는 주의해야 할 점이 하나 있습니다. name 속성을 선언(지정)하면 메서드명으로는 빈(Bean)을 주입받을 수 없게 되는데, 만약 name이 지정된 상태에서 메서드명으로 getBean( ) 메서드를 호출하면 예외가 발생하며, "sqlSessionFactory라는 이름의 빈(Bean)이 없다."라는 메시지가 출력됩니다.

 

NoSuchBeanDefinition Exception 발생

 

 

 

예외가 발생하는 걸 확인하셨다면, @Bean 어노테이션의 name 속성을 제거해 주세요.

어노테이션 name 속성 제거

 

 

마치며

이번에는 스프링 부트와 MariaDB를 연동하고, 스프링 컨테이너에 등록된 빈(Bean)을 주입받는 방법을 알아보았습니다.

 

이제, 게시판 개발을 위한 기본적인 설정 작업은 끝이 났습니다. 다음 글부터는 실제로 게시판을 구현해 보도록 하겠습니다. 여기까지 오시느라 정말 고생 많으셨습니다.

 

오늘도 글을 읽어주신 여러분께 진심으로 감사드립니다! 좋은 하루 보내세요 :)

반응형

댓글