본문으로 바로가기
반응형

[스프링부트 (4)] 스프링부트 DB 연동 (MariaDB, MyBatis, HikariCP)

 

안녕하세요. 갓대희 입니다. 이번 포스팅은 [ SpringBoot  DB 연동입니다. : ) 

 

 

0. 들어가기 앞서

Spring Boot를 사용하면서 DB를연결하기 위해 JDBC Connection Pool이란걸 사용 해보셨을 것이다.

 

▶ 커넥션풀(Connection Pool)이란?

1) 정의

 - 풀(Pool)속에 데이터베이스와의 연결(커넥션)들을 미리 만들어 두고 데이터베이스에 접근시 풀에 남아있는 커넥션중 하나를 받아와서 사용한뒤 반환하는 기법.
 - DataBase Connection Pool, DBCP라고도 한다.

 

2) 사용이유

 - 웹 애플리케이션은 다수의 사용자가 데이터베이스에 접근해야 하는 상황에 사용자들이 요청할때마다 연결을 만들고 해제하는 과정을 진행하게되면 비효율적이다.
 따라서 커넥션풀을 이용하여 미리 여러 연결을 만들어놓고 필요한 사용자가 요청시 미리 만들어놓은 연결을 주는 형식으로 효과적으로 DB연결 및 자원사용을 할 수 있다.

 

Spring Boot에 JDBC를 통해 mariadb(mysql) 연결해보자!


사실 특별한 설정이 필요하진 않다. 역시 스프링 부트 하다.
Dependency와 application.properties에 간단한 설정만 하면 MyBatis 및 MariaDB 연결은 완료 된다. (1 ~ 2번)
앞서 포스팅한 MVC의 기본 개념들을 적용하여 화면에 출력하는 것 까지 간단한 예제로 정리해 보려 한다.

 

 

1. pom.xml

▶ Dependency 추가

<!-- MariaDB -->
<dependency>
	<groupId>org.mariadb.jdbc</groupId>
	<artifactId>mariadb-java-client</artifactId>
</dependency>

<!-- mysql
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>
-->

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.1.3</version>
</dependency>

 

- gradle의 경우

compile 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3'
compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '2.7.0' // mariadb
//compile 'mysql:mysql-connector-java' //mysql

 

2. application.properties

▶ driver 및 연결 정보 설정 추가

spring.datasource.driverClassName=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=스키마계정
spring.datasource.password=비밀번호

#mysql
#spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
#spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC

 

 

3. testMapper.xml 생성

▶ mapper 추가

 - 경로 : resources\mybatis\test\testMapper.xml
 - 주의 : 향후 생성할 mapper interface에 대한 풀패키지 경로가 필요하고, 각 쿼리문의 id값과 mapper interface의 메서드명과 일치 해야 한다. 

ex) 

<?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.god.bo.test.mapper.TestMapper">
    <select id="selectTest"  resultType="com.god.bo.test.vo.TestVo">
        SELECT 'GOD' AS NAME
    </select>
</mapper>

 

※ 여기서 간단한 설정을 통해 resultType에 계속 풀패키지를 명시하지 않도록 할 수 있다.
1) application.properties 추가

# mybatis 매핑 type을 짧게 쓰기 위한 설정 
# mapper.xml에서 resultType을 지정할 때 com.god.bo.test.vo.TestVo 대신 TestVo로 간략히 할 수 있다. 
mybatis.type-aliases-package=com.god.bo.test.vo 
# mapper.xml 위치 지정 
# **은 하위 폴더 레벨에 상관없이 모든 경로를 뜻하며, *는 아무 이름이나 와도 된다는것을 뜻합니다. 
mybatis.mapper-locations=mybatis/**/*.xml

 

2) mapper.xml 에서 resultType에 클래스명만 명시

<select id="selectTest"  resultType="TestVo">
	SELECT 'GOD' AS NAME
</select>

 

 

4. Vo 클래스 생성(model, dto, vo)

 - 경로 : com.god.bo.test.vo.TestVo
 - 데이터를 관리하는 클래스, 데이터를 View로 넘겨줄때 사용하는 객체. 흔히 관념적으로 모델이라고 하며 DTO, VO 라는 표현을 많이 쓴다.

ex)

package com.god.bo.test.vo;

public class TestVo {
    private String id;
    private String name;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

 

 

5. Mapper 인터페이스 생성

 - 경로 : com.god.bo.test.mapper.TestMapper
 - 주의 : mapper.xml의 mapper tag 안에 선언한 namespace 에 정확하게 일치하는 위치에 같은 이름으로 생성해야 한다.
 그리고 select tag 안에 선언한 id 값과 각 method 이름을 같게 생성해야 한다.

ex)

package com.god.bo.test.mapper;

import java.util.List;

import com.god.bo.test.vo.TestVo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface TestMapper {
    List<TestVo> selectTest();
}

 

 

6. Service 클래스 생성

 - TestMapper interface를 autowired 하여 메서드를 콜한다.

ex) 

package com.god.bo.test.service;

import com.god.bo.test.mapper.TestMapper;
import com.god.bo.test.vo.TestVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class TestService {

    @Autowired
    public TestMapper mapper;

    public List<TestVo> selectTest() {
        return mapper.selectTest();
    }
}

 

 

7. Controller 생성 및 Service 호출

 - 위에서 생성한 Service의 메서드를 호출하는 Controller를 생성 하도록 하자.

ex) 

@Autowired
TestService testService;

@RequestMapping(value = "/test")
public ModelAndView test() throws Exception{
    ModelAndView mav = new ModelAndView("test");

    List<TestVo> testList = testService.selectTest();
    mav.addObject("list", testList);

    return mav;
}

 

 

8. 화면에 맞게 출력하자.

ex)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>View Test Page</title>
</head>
<body>
    <h2>Hello!</h2>
    <div>JSP List Test</div>
    <c:forEach var="item" items="${list}" varStatus="idx">
        ${idx.index}st, Hello! ${item.name} <br />
    </c:forEach>
</body>
</html>

 

Application을 실행하여 해당하는 경로의 페이지를 호출하여 보자.

올바르게 데이터 베이스가 연동 되어, 화면에 노출되는것을 볼 수 있다. 

여기까지 했다면 Mybatis, MariaDB연동에 성공 하였다.

 

 

9. HikariCP

1) Spring Boot 2.0 이전 : Tomcat JDBC Connection Pool를 Default로 사용하였다.
2) Spring Boot 2.0 이후 : HikariCP를 Default로 사용하고 있다.
3) hikariCP github사이트에서는 매우 빠르고, 가볍고, 신뢰할 수 있다고 설명한다.
4) "zero-overhead" 엄청나게 높은 성능이라고 강조하며 tomcat, dbcp 등과의 성능 비교 결과도 첨부하고 있다.

사진 출처 : https://github.com/brettwooldridge/HikariCP



결국 예전 버전에서는 명시하여 사용해야했지만, 이제는 application.properties에 간단한 설정만 한다면 쉽게 사용할 수 있다.

 

▶ 설정 예시

#MariaDB
spring.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:mariadb://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC
#Hikari
spring.datasource.hikari.username=username
spring.datasource.hikari.password=password
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.connection-test-query=SELECT 1

 

혹시나 하여 HikariConfig클래스 파일도 확인해 보았다.

여러 프로퍼티를 설정할수 있는 것 같다.

 

▶ HikariCP 옵션

 -  HikariCP 옵션 (다음 github에서 더 자세히 나와 있다.)

참고 : https://github.com/brettwooldridge/HikariCP 

 - HikariCP설정의 시간 단위는 밀리세컨즈(ms)이다.

 

◎ autoCommit (default: true) - auto-commit설정 

◎ connectionTimeout (default : 30000(30초))
 - 풀에서 커넥션을 얻어오기전까지 기다리는 최대 시간, 허용가능한 wait time을 초과시 SQLException이 발생한다.
 - 설정가능한 최소 값 : 250

◎ validationTimeout (default : 5000(5초))
 - valid 쿼리를 통해 커넥션이 유효한지 검사할 때 사용되는 timeout시간.(커넥션이 유효 검사 시 대기 시간을 지정)
 - 이 값은 connectionTimeout보다 작아야 한다.
 - 설정가능한 최소 값 : 250

◎ maximumPoolSize (default: 10)
 - 풀에 유지시킬 수 있는 최대 커넥션 수.
 - 풀의 커넥션 수가 옵션 값에 도달하게 되면 idle인 상태는 존재하지 않는다.
 - 풀이 이 크기에 도달하고 유휴 커넥션이 없을 때 connectionTimeout이 지날 때까지 getConnection() 호출은 블록킹된다.

◎ idleTimeout (default : 600000(10분))
 - pool에 일하지 않는 커넥션을 유지하는 시간.
 - 이 옵션은 minimumIdle이 maximumPoolSize보다 작게 설정되어 있을 때만 적용된다.
 - 이 옵션이 0이면 유휴 커넥션을 풀에서 제거하지 않는다.
 - 설정가능한 최소 값 : 10000(10초)

◎ minimumIdle (default: same as maximumPoolSize)
 - 유휴 커넥션의 최소 개수(아무런 일을 하지않아도 적어도 이 옵션 값의 size로 커넥션들을 유지해주는 설정이다.)
 - default값이 유동적이기 때문에 최적의 성능과 응답성을 생각하면 구지 설정하지 않는게 좋을 것 같다.

◎ maxLifetime (default : 1800000(30분))
 - 커넥션의 최대 유지 시간. 이 시간이 지난 커넥션 중에서 사용중인 커넥션은 종료된 이후에 풀에서 제거한다.
 - 갑자기 풀에서 많은 커넥션이 제거되는 것을 피하기 위해 negative attenuation을 적용해 점진적으로 제거한다.
 - 이 값이 0이면 풀에서 제거하지 않지만 idleTimeout은 적용된다.
 
◎ connectionTestQuery (default : 없음)
 - 커넥션이 유효한지 검사할 때 사용할 쿼리를 지정한다.(보통 SELECT 1 로 설정 한다.)
 - 드라이버가 JDBC4를 지원하면 이 프로퍼티를 설정하지 말자.(이 프로퍼티를 설정하지 않으면 JDBC4의 Conneciton.isValid()를 사용하여 유효성 검사 수행)
 - JDBC4 드라이버를 지원하지않는 환경에서 이 값을 설정하지 않는다면 error레벨 로그 리턴.

◎ leakDetectionThreshold
 - 커넥션이 누수 로그메시지가 나오기 전에 커넥션을 검사하여 pool에서 커넥션을 내보낼 수 있는 시간 설정.
 - 0으로 설정하면 누수 발견을 하지 않는다(leak detection 이용하지 않음). 허용하는 최소 값은 2000(2초)이다.
 - 설정가능한 최소 값 : 2000(2초)

 

 

반응형

댓글을 달아 주세요

  1. BlogIcon 임동임둥 2020.02.13 17:01

    디비연동이 막혀서 스프링공부도 잠시 접었는데 이 글을 보고 다시 도전해야겠네요!

  2. 곽효영 2020.02.13 19:17

    히카리 ^^
    스프링부트 셋팅은 데모 알집이 갑이지

  3. 뚜벅초 2020.04.02 14:14

    pom.xml 에 dependency 추가할 때, myBatis 관련된 건 추가 안해도 되는건가요??
    추가를 안할 경우 TestMapper 에 @Mapper 어노테이션 에러가 발생하네요.

    • <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.1</version>
      </dependency>

      네 ㅠㅠ 그부분을 빼놓고 작성했네요.
      넣어주시면 될 것 같아요~

    • BlogIcon GG 2020.07.16 18:32

      mybatis 관련 라이브러리에서 버전이 안맞아서
      https://mvnrepository.com/
      참고하여


      <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.3</version>
      </dependency>

      <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.3</version>
      </dependency>

      <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.1</version>
      </dependency>


      이렇게 작성하니 Mapper Import되네요 같은문제 있으신분 한번해보세요

  4. 으어어 2020.05.18 01:12

    오라클, Mybatis를 사용하는데

    오라클 세팅도 알려주실 수 있으신가요?ㅠㅠ

  5. 흠냥 2020.06.03 04:02

    안녕하세요

    전 신기하게

    ### SQL: SELECT 'GOD' AS NAME ### Cause: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
    org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
    ### Error querying database. Cause: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

    이런 오류가 뜨는데

    왜 나는걸까요;;

  6. 스린이 2020.11.26 12:28

    java.lang.IllegalStateException: Cannot load driver class: org.mariadb.jdbc.Driver 이오류가 뜨는데

    pom.xml에 디펜던시 추가 했고
    application.properties에 아이디비밀번호 확인하고 실행했는데 왜 뜨는건가요/
    mariadb도 설치했습니다..

    • 개발 환경에따라, 혹은 오타에 따라 다 다를 수 있을 것 같은데

      지금 당장 생각날만한 내용은 혹시 자바 버전에 따라 mariadb 버전 변경을 해보시는 시도도 해보셨을까요.

      https://mariadb.com/kb/en/about-mariadb-connector-j/

  7. ros0126 2021.05.03 12:36

    gradle 방식이랑 maven 방식은 차이가 뭔가요? 스프링첨할때 매퍼등등 위의 것처럼 디비연결하였는데 스프링보트 공부하려고하니까 gradle을 많이쓰는것같은데 어떻게 연결해야하는건지 어렵네요 ㅠㅠ