H2 Database
개요
Spring 프로젝트를 생성하여 열심히 코드를 작성했다. 그리고 작성한 기능들이 잘 동작하는지 확인하고싶어서 계층 테스트 뿐만 아니라 통합테스트도 작성하였다.
이제 PR을 날릴 때마다 CI를 돌리며 이상이 없는지 확인하고 빠르게 통합하면 된다.
그러나… 데이터베이스를 사용하는 통합테스트라던가 어떻게 동작하게될까?
실제 DB는 클라우드에 있을 텐데 PR마다 이 DB를 직접 연결해서 테스트하는 걸까? 데이터가 꼬이진 않을까?
H2 Database
H2는 Hypersonic 2라는 의미로 극초음속, 그러니까 어찌되었건 매우 빠르다는 의미다.
H2는 테스트나 개발 환경에 특화된 설계를 가지고 있는데 여러 특징이 있다.
- 인메모리 방식 지원 디스크가 아닌 메모리에 데이터를 올려서 읽고 쓰기 때문에 IO병목 현상이 일어나지 않는다. 애초에 디스크 읽기/쓰기 비용이 사라지니 빠르다.
- JVM 내에세 바로 실행 가증 H2는 순수 자바로 구현되어 JVM 내에서 바로 실행이 가능하다. 네트워크 통신 없이 내장 모드로 애플리케이션과 동일 프로세스에서 실행되니 오버헤드가 없다.
- 가벼운 구조 다른 DB들과 다르게 필수 기능 중심으로만 설계되어있다.
- 스키마 초기화와 테이블 생성이 빠름
- 불필요한 JDBC 계층 동작 없이 바로 처리되기 때문에 쿼리 실행 속도가 빠르다.
위에서 말한 궁금증의 답은 Spring boot에서 data-jpa 의존성을 추가하면 자동으로 h2를 기본 데이터베이스로 설정해준다.
따라서 CI/CD 가상 환경에서 테스트를 할 시 가상의 데이터베이스를 사용해야하는데 JPA의존성을 추가할 때 h2를 사용하여 테스트하는 것이다.
그러나 안전성이 중요한 경우 H2는 위에서 말했던 대로 실제 DB와는 차이가 있을 수 있다. 이럴 때는 테스트 컨테이너를 사용하여 테스트하는 방법을 고려해볼 수 있다.
사용법
위에서 h2를 디폴트로 사용한다고 해서 jpa에 h2의존성이 포함된 것은 아니다.
마치 환자에게 수액을 놓으려면 우선 라인을 잡아야하는데 라인을 잡았다고 해도 수액을 연결하지 않으면 의미가 없는 것과 마찬가지다.
따라서 우선 h2 의존성을 설정해야한다.
implementation 'com.h2database:h2'
implementation VS runtimeOnly
의존성을 추가할 때 종종 위의 두 가지 키워드를 볼 수 있다.
둘의 차이는 쉽게 말하면 코드를 직접 참조할 때, 실행 시에만 필요한 경우로 볼 수 있다.
예를 들어 롬복의 경우 코드 파일에서 import lombok과 같이 직접 import해서 사용할 경우 컴파일러가 해당 클래스를 읽어야하기 때문에 implementaion이 필요하다. 반면 h2의 경우 우리가 직접 호출하는 코드가 아니기에 runtimeOnly로만 사용해도 충분하다. 마찬가지로 testImplementation은 src/test/java에 있는 테스트 코드들이 컴파일 될 때 필요한 의존성을 넣을 때 사용한다. 이렇게 하면 컴파일 속도에서 이점을 얻을 수 있다.
크게 2가지 방법으로 사용할 수 있다.
하나는 일반적인 DB 같이 사용하는 서버 모드, 다른 하나는 테스트 환경과 같이 임시 환경에서 사용하는 인메모리 모드(임베디드)
만약 인메모리 모드로 사용하려고 한다면 application.yml에서 다음과 같이 설정한다.
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:{DB 이름}
username: sa
password:
다른 DB 모드로 설정하려면 다음과 같이 할 수 있다.
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb;MODE=MySQL
username: sa
password:
이렇게 하면 쿼리 문법 차이로 인한 오류를 줄일 수 있다.
h2는 디폴트로 sa라는 유저네임을 사용하는데 이는 System Administrator, Super Admin등을 뜻한다. mysql에서 루트 계정 유저네임을 root로 사용하는 것과 같이 큰 의미가 없는 기본값으로 변경해도 무방하다.
이렇게 구동시키고 인텔리제이에서 접속정보를 넣고 접속해볼 수도 있고 h2 콘솔을 사용해볼 수도 있다. yml에서 spring 바로 아래 계층에
h2:
console:
enabled: true
설정을 넣어주고 localhost:8080/h2-console과 같이 입력해보면 콘솔 창이 생긴다.
다음으로 파일 모드로 사용하려면 url을 다음과 같이 명시하면 된다.
url: jdbc:h2:file:./data/testdb
이렇게 하면 db 파일이 ./이하의 경로에 생성되고 서저가 재시작된 후에도 유지된다.
실질적으로 h2 db를 사용하는 경우는 테스트를 돌릴 경우이므로 사용법을 정리해보자면…
가장 쉽게는 src/test/resources 내부에 application.yml 파일을 만들어서 여기에 디테일한 부분을 설정하면 된다.
Junit 테스트가 실행되면 이 곳에 있는 설정이 가장 우선적으로 로딩되기 때문이다.
이것 말고도 다른 상황이 있을 수 있다.
그럴 때 사용할 수 있는 설정은 프로파일 시스템으로
application-test, application-prod와 같이 여러개의 설정을 작성하고 개발자가 설정한 설정을 읽어들인다.
테스트 환경에서도 마찬가지로
@ActiveProfiles("test")
와 같이 작성하면 테스트 프로파일을 적용하여 실행하게 된다.