[h2]DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;
제이슨의 JPA수업 도중 application.properties의 설정에서 아래와 같은 h2 설정이 있었다.
spring.datasource.url=jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
h2설정할 때, 어쩔때는 h2:mem, h2:tcp였고 이번에는 그냥 h2:~였다. 또한 DB_CLOSE~라는 새로운 이름도 보여서 h2에 대해서 조금 공부해보려고 한다.
Connection Modes
- Embedded mode (local connections using JDBC)
- Server mode (remote connections using JDBC or ODBC over TCP/IP)
- Mixed mode (local and remote connections at the same time)
이 3가지중 자주 사용하는 Embedded와 Server모드에 대해서만 알아보겠다.
Embedded mode
임베디드 모드에서는 애플리케이션이 JDBC를 사용하여 동일한 JVM 내에서 데이터베이스를 엽니다.
장점으로는 가장 빠르고 쉬운 연결 모드이다.
단점은 데이터베이스가 한 번에 하나의 virtual machine(및 클래스 로더)에서만 열릴 수 있다는 것이다.
I/O 작업은 SQL 명령을 실행하는 응용 프로그램의 스레드에 의해 수행될 수 있다. 애플리케이션이 이러한 스레드를 중단하지 않을 수 있으며, 스레드 중단 중에 JVM이 I/O 핸들을 닫기 때문에 데이터베이스가 손상될 수 있다.
Server Mode
서버 모드를 사용할 때 응용 프로그램은 JDBC 또는 ODBC API를 사용하여 원격으로 데이터베이스를 연다.
많은 응용프로그램이 이 서버에 연결하여 동일한 데이터베이스에 동시에 연결할 수 있습니다. 내부적으로 서버 프로세스는 데이터베이스를 임베디드 모드로 엽니다.
모든 데이터가 TCP/IP를 통해 전송되기 때문에 서버 모드는 내장 모드보다 느리다.
Connecting to an Embedded (Local) Database
jdbc:h2:[file:][<path>]<databaseName>
jdbc:h2:~/test
jdbc:h2:file:/data/sample
jdbc:h2:file:C:/data/sample (Windows only)
와 같은 url 포멧일 때, 사용된다.
[file:]은 option으로 안 적거나 상대경로를 적어야 한다. path와 databaseName은 os마다 다르지만 소문자로 적는 것을 공식문서에서 추천한다. databaseName은 3글자 이상이어야 하고 이름에는 세미콜론을 사용할 수 없다.
사용자 홈 디렉토리를 가리키려면 다음과 같이 ~/를 사용한다. jdbc:h2:~/test.
In-Memory Databases
신속한 프로토타이핑, 테스트, 고성능 운영, 읽기 전용 데이터베이스와 같이 데이터를 유지하거나 데이터를 변경하지 않아도 될때 사용하는게 좋다. 인메모리 디비는 데이터가 지속되지 않는다.
데이터베이스 URL은 jdbc:h2:mem: 을 통해서 새로운 커넥션으로 새로운 (private)디비를 생성할 수 있다.
하나의 디비에 다중 연결이 필요할 때는 jdbc:h2:mem:db1와 같이 이름을 붙여서 사용할 수 있다.
또 다른 컴퓨터에서 tcp를 통해 접근하려면 jdbc:h2:tcp://localhost/mem:db1와 같이 사용할 수 있다.
기본적으로 데이터베이스에 대한 마지막 연결을 닫으면 데이터베이스가 닫힌다. 인메모리 디비에서는 내용이 사라진다.
데이터베이스를 열린 상태로 유지하려면 데이터베이스 URL에;DB_CLOSE_DELAY=-1을 추가하면 된다.
즉, jvm이 살아있는 동안 메모리 내 데이터베이스의 내용을 유지하려면 jdbc:h2:mem:test;DB_CLOSE_DELay=-1을 하자.대신 이때 SHUTDOWN 명령을 사용하여 DB를 닫을때는 메모리 누수가 발생할 수 있다고 한다.(그런데 DB에 대한 마지막 커넥션이 닫히면 DB가 자동으로 닫히므로 SHUTDOWN명령어를 쓸 일은 없다고 보면 된다.)
;DB_CLOSE_ON_EXIT=FALSE(VM 종료 시 데이터베이스 닫기 안 함)
디비가 마지막 커넥션이 끊겼는데도 정상적으로 닫히지 않는다면 vm이 정상적으로 종료될 때, shutdown hook를 사용하여 디비를 닫는다고 한다.
이 경우 vm 종료 시 데이터베이스가 계속 사용되므로(예: 종료 프로세스를 데이터베이스에 저장하기 위해) 이 경우 데이터베이스를 닫지 않아야 한다.
이때 DB_CLOSE_ON_EXIT설정으로 데이터베이스 자동 닫기를 사용 불가능으로 설정할 수 있다. 즉, 예상치 못한 디비의 셧다운을 막아주도록 한다.
server mode
서버 모드도 내부적으로 서버 프로세스는 데이터베이스를 임베디드 모드로 열지만, 데이터의 처리 흐름이 TCP/IP를 통하여 전송되기 때문에 임베디드 모드보다는 느리다.
결론
h2는 용량이 작아서 상용보다는 주로 테스트에서 사용했다. 빠르게 테스트를 하고 결과를 구하기 위해서 서버 모드보다는 임베디드 모드가 더 좋은 것 같다.
또한 jdbc:h2:~/test 로 임베디드 모드로 url을 적는 경우는 test.mv.db 라는 file이 남아서 나중에 다른 애플리케이션에서 h2로 테스트를 할 때, 파일 이름이 겹쳐서 안되는 경우가 발생할 수 있으므로 매번 다른 이름으로 설정해야 한다는 번거러움이 있을 것 같다.
또한 주로 테스트 용도로 h2를 사용하므로 공식문서에서도 말하듯 테스트를 할땐 인메모리 모드로 사용하는것을 추천한다.
그리고 아직까지 mv.db파일을 활용할 일이 없어서 jdbc:h2:mem:test와 같은 url 이름으로 인메모리 디비를 사용하여 파일을 남지 않게 하는 것도 방법일것같다.
또한 ;DB_CLOSE_DELAY=-1 은 인메모리 디비에서만 사용된다. 커넥션이 다 끊겨도 디비가 닫히지 않는다면 디비는 자동으로 종료된다. 인메모리 디비에서 디비가 자동으로 종료되지 않도록 해준다.
;DB_CLOSE_ON_EXIT=FALSE는 임베디드 디비에서 사용하며 디비가 자동으로 종료되는 것을 막아준다. 이렇게 디비의 자동 종료를 비활성화하면 데이터베이스가 닫히는 시간을 스프링 부트가 제어할 수 있으므로 데이터베이스에 대한 액세스가 더 이상 필요하지 않을 때 발생하도록 보장한다.
@AutoConfigureTestDatabase에서도 이렇게 설정된 이유가 위와 같은 이유때문일것 같다.
Reference
http://www.h2database.com/html/features.html#in_memory_databases
https://docs.spring.io/spring-boot/docs/1.4.3.RELEASE/reference/html/boot-features-sql.html