스프링부트가 지원하는 인메모리 데이터베이스에 대해 알아보자.

인메모리 데이터베이스

인메모리 데이터베이스는 말 그대로 애플리케이션 서버의 메모리를 이용하는 데이터베이스 시스템을 말한다.

지원하는 데이터베이스의 종류는 다음과 같다.

  • H2
  • HSQL
  • Derby

실습

스프링부트에서 스프링 JDBC 의존성이 클래스패스에 있는 경우, DataSource와 JdbcTemplate이 자동 설정된다. (DataSourceAutoConfiguration와 JdbcTemplateAutoConfiguration에서 확인이 가능하다)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

h2 의존성이 클래스패스에 있고, DataSource에 대한 아무런 설정도 하지 않았다면 스프링부트가 자동으로 h2를 인메모리 데이터베이스를 설정한다.

ApplicationRunner를 이용해 DataSource의 정보를 확인해보자.

@Component
public class H2Runner implements ApplicationRunner {

    @Autowired
    DataSource dataSource;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Connection connection = dataSource.getConnection();
        System.out.println("===============");
        System.out.println(connection.getMetaData().getURL());
        System.out.println(connection.getMetaData().getUserName());
    }
}

H2Ruuner를 작성하고 빈으로 등록한 뒤 앱을 실행하면 URL은 "jdbc:h2:mem:testdb", userName은 "SA"가 출력된다. 이런 정보는 DataSourceAutoConfiguration에서 자동으로 설정한다. 해당 클래스에서 EmbeddedDatabaseConfiguration를 등록하는 부분을 보면, EmbeddedDataSourceConfiguration를 import하는 것을 알 수 있다. EmbeddedDataSourceConfiguration의 코드를 열어보자.

@Bean
public EmbeddedDatabase dataSource() {
    this.database = new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseConnection.get(this.classLoader).getType())
        .setName(this.properties.determineDatabaseName()).build();
    return this.database;
}

EmbeddedDataSourceConfiguration가 DataSource를 등록하는 것을 알 수 있다. EmbeddedDataSourceConfiguration는 생성자에서 DataSourceProperties를 properties라는 인스턴스 변수로 주입받는다. DataSourceProperties는 이름에서 알 수 있듯이, DataSource의 프로퍼티에 관련된 클래스로서 dbname, url, userName 등을 결정하거나 반환한다.

다시 실습으로 돌아와서, 러너에서 테이블을 만들어보자.

@Component
public class H2Runner implements ApplicationRunner {

    @Autowired
    DataSource dataSource;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        try (Connection connection = dataSource.getConnection()) {
            System.out.println("===============");
            System.out.println(connection.getMetaData().getURL());
            System.out.println(connection.getMetaData().getUserName());

            Statement statement = connection.createStatement();
            String sql = "CREATE TABLE USER(ID INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id))";
            statement.executeUpdate(sql);
        }
    }
}

JDBC를 이용해 USER 테이블을 만드는 코드를 작성하고 (트랜잭션, 롤백과 같은 세부사항은 제외) 앱을 실행하면 정상적으로 동작하는 것을 알 수 있다. H2가 제공하는 콘솔을 이용해 USER 테이블이 생성되었는지 확인해보자.

H2 콘솔

spring-boot-devtools를 추가하거나 spring.h2.console.enabled=true를 추가하면 H2 콘솔을 사용할 수 있다. application.properties에 spring.h2.console.enabled=true를 추가하고 /h2-console로 접속해보자. (해당 경로는 변경할 수 있다)

웹콘솔에 접속한 뒤, 연결정보(jdbc:h2:mem:testdb, sa)를 입력하고 connect 버튼을 클릭하면 콘솔화면이 나타난다. 정상적으로 접속되었다면 USER 테이블이 생성되어있는 것을 볼 수 있다.

이번에는 JdbcTemplate를 이용하여 INSERT 쿼리를 실행해보자. 좀 더 간결하고 안전하게 쿼리를 작성할 수 있다.

@Override
public void run(ApplicationArguments args) throws Exception {
    try (Connection connection = dataSource.getConnection()) {
        System.out.println("===============");
        System.out.println(connection.getMetaData().getURL());
        System.out.println(connection.getMetaData().getUserName());

        Statement statement = connection.createStatement();
        String sql = "CREATE TABLE USER(ID INTEGER NOT NULL, name VARCHAR(255), PRIMARY KEY (id))";
        statement.executeUpdate(sql);
    }

    jdbcTemplate.execute("INSERT INTO USER VALUES (1, 'jch')");
}

앱을 재구동하여 콘솔에서 SELECT 쿼리로 확인해보면 추가된 사용자 정보를 조회할 수 있다.

JdbcTemplate를 이용하면 리소스 반납 처리, 계층구조가 잘 잘 구성되어 가독성 높은 예외를 사용하는 등의 장점을 누릴 수 있다.

해당 포스팅은 스프링 부트 개념과 활용 강의 내용을 토대로 작성하였습니다.