Dico

Spring Boot, H2 Database 외부 접속하기

H2 Database

    In-memory Database인 H2를 Spring Boot로 띄울 경우 기본적으로 JVM 메모리에 탑재합니다. JVM 메모리에 올라가 있으면 H2를 외부에서 접근할 수 없습니다. 데이터를 확인하기 위해서는 H2 Console을 활용하거나, 별도의 방법으로 우회해야 됩니다.

H2 Console

h2 console

    H2 Console를 사용하기 위해서는 두 가지 방법 중 하나를 적용하면 됩니다.

  1. 프로젝트 설정, spring-boot-devtools 추가
  2. 프로퍼티, spring.h2.console.enabled=true 추가

devtools를 사용할 경우 다양한 설정을 추가하는데, 그 중 하나가 2번 프로퍼티 설정입니다. 

굳이 devtools를 사용하고 싶지 않다면 해당 프로퍼티만 설정하면 됩니다.

기본적으로 localhost/h2-console 으로 접근할 수 있으며, path는 설정을 통해 변경할 수 있습니다.

spring:
   h2:
      console:
         enabled: true
         path: /h2 # default /h2-console

    당연한 이야기지만, PhpMyAdmin처럼 외부에 노출되서 좋을게 없으므로 개발 용도로만 사용해야 합니다. 또한 웹 콘솔은 사용성도 떨어지고, 기능적인 한계가 명확합니다. 이를 해결하기 위해 다음과 같이 우회를 시도할 수 있습니다.

H2 외부 접속 활성화 방법

    H2 TCP Server로 우회하는 방법이 있습니다. H2 라이브러리는 다양한 기능을 제공하는데, 그 중 하나입니다. Spring Boot version에 따라 동작이 미묘하게 달라지는 듯 하여 고생하였습니다. 다른 사람의 글도 그렇고, H2 공식문서조차 TCP를 통하여 In-memory 접근을 할 수 있는 것처럼 되어 있으나, Spring Boot는 오류를 반환합니다. 이 글은 Spring Boot 2.1.6 기준으로 작성하였습니다.

h2 docs

    Database Client는 IntelliJ Ultimate Database를 활용하였습니다.

IntelliJ Ultimate Database

    IntelliJ의 유료 버전인 Ultimate는 database Client 기능이 존재합니다. 커뮤니티 버전은 해당되지 않습니다. 이 기능을 통하여 H2 Database를 접근할 때 file로 직접 접근하면 테이블을 불러오지 못 합니다. H2 TCP Server를 사용하는 이유가 바로 여기에 있습니다.

IntelliJ

프로젝트 설정

    우선 Gradle 프로젝트 설정을 변경해야 합니다. H2 라이브러리를 가져올 때 기본적으로 runtimeOnly로 설정 되어 있는데, 이를 complie로 변경해야 합니다. runtime으로 설정된 경우 코드 작성 시 H2 라이브러리를 호출하지 못 합니다.

compile 'com.h2database:h2' // default runtimeOnly


    jdbc-url을 입력할 때는 파일 embedded path로 적어도 되며, TCP Server mode로 적어도 동작에는 문제 없습니다. 협업을 위한다면 다른 사람들이 헷갈리지 않도록 TCP Server mode로 적어둡시다. 단, 그럴 경우 embedded file을 미리 생성해놓아야 합니다. embedded file이 없을 경우 오류가 발생합니다.

# application-local.yml
spring:
  datasource:
    hikari:
      driver-class-name: org.h2.Driver
      jdbc-url: jdbc:h2:./data/testdb # ./ Project root
      # OR jdbc-url: jdbc:h2:tcp://localhost:9092/./data/testdb
      username: sa
      password:

    프로퍼티에 주목할 부분이 있는데, 바로 hikari입니다. tcp로 우회하기 위해서는 HikariCP의 jdbc-url로 설정해야 오류가 발생하지 않습니다. 만약 일반적인 방법으로 hikari가 아니라 datasource에 작성할 경우 다음과 같이 오류를 반환합니다.

# 아래와 같이 datasource에 설정하면 오류가 발생한다.
spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:./data/testdb
    username: sa
    password:

IntelliJ

    다음 코드를 통해 H2 TCP Server를 활성화합니다. 이 코드는 포트 번호로 9092를 주었으며, 다른 포트로 변경해도 됩니다. 프로파일 설정을 통해 local인 경우에만 TCP Server가 열리도록 설정하였습니다.

import org.h2.tools.Server;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@Profile("local")
public class H2ServerConfiguration {

    @Bean
    @ConfigurationProperties("spring.datasource.hikari")
    public DataSource dataSource() throws SQLException {
        Server.createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", "9092").start();

        return new com.zaxxer.hikari.HikariDataSource();
    }
}

IntelliJ 설정

IntelliJ

IntelliJ

    위와 같이 설정하면 H2 Database를 접근 할 수 있으며, IDE에서 다음과 같이 SQL를 요청하여 데이터를 확인할수 있습니다.

IntelliJ

    사실 웹 콘솔을 통해서도 데이터를 확인할 수 있기 때문에, 이처럼 설정하지 않아도 됩니다. 다만 조금이라도 편하게 개발하고 싶은 마음이 컸으며, 나중에 협업을 할 때 Local 데이터를 공유할 수도 있다고 생각하였습니다. H2 Database를 파일로 남길 경우 파일 공유만으로 다른 개발자와 동일한 테스트 데이터를 유지할 수 있습니다. 물론 개발용 데이터베이스 서버를 만들어서 활용해도 되지만, 어디까지나 제가 원한건 편리한 Local 환경 구축이었습니다. Hibernate의 ddl-auto 기능을 편안하게 사용하기 위해서는 전체가 공유하는 개발용 데이터베이스가 아니라 Local용 데이터베이스여야 합니다.

    이제서야 Spring Boot를 공부하는 입장이라 간단한 설정임에도 불구하고 이틀이라는 시간이 걸렸지만, 웹 콘솔만으로 개발하는 속도를 생각하면 충분히 가치있는 삽질이었습니다. 삽질을 하며 배운 것도 많아 다행입니다.