-
[김영한 스프링] 09. 데이터 접근 기술(테스트) - 임베디드 모드 DB & 스프링 부트와 임베디드 모드Spring/스프링 DB 2편 - 데이터 접근 활용 기술 2024. 1. 9. 14:13
테스트 - 임베디드 모드 DB
테스트 케이스를 실행하기 위해서 별도의 데이터베이스를 설치하고, 운영하는 것은 상당히 번잡한 작업이다. 단순히 테스트를 검증할 용도로만 사용하기 때문에 테스트가 끝나면 데이터베이스의 데이터를 모두 삭제해도 된다. 더 나아가서 테스트가 끝나면 데이터베이스 자체를 제거해도 된다.
임베디드 모드
H2 데이터베이스는 자바로 개발되어 있고, JVM안에서 메모리 모드로 동작하는 특별한 기능을 제공한다. 그래서 애플리케이션을 실행할 때 H2 데이터베이스도 해당 JVM 메모리에 포함해서 함께 실행할 수 있다. DB를 애플리케이션에 내장해서 함께 실행한다고 해서 임베디드 모드(Embedded mode)라 한다. 물론 애플리케이션이 종료되면 임베디드 모드로 동작하는 H2 데이터베이스도 함께 종료되고, 데이터도 모두 사라진다. 쉽게 이야기해서 애플리케이션에서 자바 메모리를 함께 사용하는 라이브러리처럼 동작하는 것이다.
이제 H2 데이터베이스를 임베디드 모드로 사용해 보자.
임베디드 모드 직접 사용
ItemServiceApplication - 추가
package hello.itemservice; import hello.itemservice.config.*; import hello.itemservice.repository.ItemRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; @Slf4j @Import(JdbcTemplateV3Config.class) @SpringBootApplication(scanBasePackages = "hello.itemservice.web") public class ItemServiceApplication { public static void main(String[] args) { SpringApplication.run(ItemServiceApplication.class, args); } @Bean @Profile("local") public TestDataInit testDataInit(ItemRepository itemRepository) { return new TestDataInit(itemRepository); } @Bean @Profile("test") public DataSource dataSource() { log.info("메모리 데이터베이스 초기화"); DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; } }
- @Profile("test")
- 프로필이 test 인 경우에만 데이터소스를 스프링 빈으로 등록한다.
- 테스트 케이스에서만 이 데이터소스를 스프링 빈으로 등록해서 사용하겠다는 뜻이다.
- dataSource()
- jdbc:h2:mem:db : 이 부분이 중요하다. 데이터소스를 만들때 이렇게만 적으면 임베디드 모드(메모리 모드)로 동작하는 H2 데이터베이스를 사용할 수 있다.
- DB_CLOSE_DELAY=-1 : 임베디드 모드에서는 데이터베이스 커넥션 연결이 모두 끊어지면 데이터 베이스도 종료되는데, 그것을 방지하는 설정이다.
- 이 데이터소스를 사용하면 메모리 DB를 사용할 수 있다.
실행
- 그런데 막상 실행해 보면 다음과 같은 오류를 확인할 수 있다.
- 참고로 오류는 항상 아래에 있는 오류 정보가 더 근본 원인에 가까운 오류 로그이다.
- Table "ITEM" not found이 부분이 핵심이다. 데이터베이스 테이블이 없는 것이다.
- 생각해보면 메모리 DB에는 아직 테이블을 만들지 않았다.
테스트를 실행하기 전에 테이블을 먼저 생성해주어야 한다. 수동으로 할 수도 있지만 스프링 부트는 이 문제를 해결할 아주 편리한 기능을 제공해 준다.
스프링 부트 - 기본 SQL 스크립트를 사용해서 데이터베이스를 초기화하는 기능
메모리 DB는 애플리케이션이 종료될 때 함께 사라지기 때문에, 애플리케이션 실행 시점에 데이터베이스 테이블도 새로 만들어주어야 한다.
JDBC나 JdbcTemplate를 직접 사용해서 테이블을 생성하는 DDL을 호출해도 되지만, 너무 불편하다. 스프링 부트는 SQL 스크립트를 실행해서 애플리케이션 로딩 시점에 데이터베이스를 초기화하는 기능을 제공한다.
drop table if exists item CASCADE; create table item ( id bigint generated by default as identity, item_name varchar(10), price integer, quantity integer, primary key (id) );
test/resources/schema.sql 생성
참고
SQL 스크립트를 사용해서 데이터베이스를 초기화하는 자세한 방법은 다음 스프링 부트 공식 메뉴얼을 참고하자.
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.datainitialization.using-basic-sql-scripts실행
테스트 - 스프링 부트와 임베디드 모드
스프링 부트는 개발자에게 정말 많은 편리함을 제공하는데, 임베디드 데이터베이스에 대한 설정도 기본으로 제공한다.
스프링 부트는 데이터베이스에 대한 별다른 설정이 없으면 임베디드 데이터베이스를 사용한다.
앞서 직접 설정했던 메모리 DB용 데이터소스를 주석처리하자.
ItemServiceApplication
package hello.itemservice; import hello.itemservice.config.*; import hello.itemservice.repository.ItemRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; @Slf4j @Import(JdbcTemplateV3Config.class) @SpringBootApplication(scanBasePackages = "hello.itemservice.web") public class ItemServiceApplication { public static void main(String[] args) { SpringApplication.run(ItemServiceApplication.class, args); } @Bean @Profile("local") public TestDataInit testDataInit(ItemRepository itemRepository) { return new TestDataInit(itemRepository); } // @Bean // @Profile("test") // public DataSource dataSource() { // log.info("메모리 데이터베이스 초기화"); // DriverManagerDataSource dataSource = new DriverManagerDataSource(); // dataSource.setDriverClassName("org.h2.Driver"); // dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1"); // dataSource.setUsername("sa"); // dataSource.setPassword(""); // return dataSource; // } }
application.properties
spring.profiles.active=test #spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase #spring.datasource.username=sa #spring.datasource.password= #jdbcTemplate sql log logging.level.org.springframework.jdbc=debug
이렇게 하면 데이터베이스에 접근하는 모든 설정 정보가 사라지게 된다.
이렇게 별다른 정보가 없으면 스프링 부트는 임베디드 모드로 접근하는 데이터소스(DataSource)를 만들어서 제공한다. 바로 앞서 우리가 직접 만든 데이터소스와 비슷하다 생각하면 된다.
실행
jdbc:h2:mem 뒤에 임의의 데이터베이스 이름이 들어가 있다. 이것은 혹시라도 여러 데이터소스가 사용될 때 같은 데이터베이스를 사용하면서 발생하는 충돌을 방지하기 위해 스프링 부트가 임의의 이름을 부여한 것이다.
임베디드 데이터베이스 이름을 스프링 부트가 기본으로 제공하는 jdbc:h2:mem:testdb로 고정하고 싶으면 application.properties에 다음 설정을 추가하면 된다.
spring.datasource.generate-unique-name=false
참고
임베디드 데이터베이스에 대한 스프링 부트의 더 자세한 설정은 다음 공식 메뉴얼을 참고하자.
https://docs.spring.io/spring-boot/docs/current/reference/html/data.html#data.sql.datasource.embedded출처 : https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard
'Spring > 스프링 DB 2편 - 데이터 접근 활용 기술' 카테고리의 다른 글
[김영한 스프링] 11. MyBatis - 적용 (0) 2024.01.09 [김영한 스프링] 10. MyBatis - 소개 & 설정 (0) 2024.01.09 [김영한 스프링] 08. 데이터 접근 기술(테스트) - 데이터 롤백 & @Transactional (0) 2024.01.09 [김영한 스프링] 07. 데이터 접근 기술(테스트) - 데이터베이스 연동 & 분리 (0) 2024.01.09 [김영한 스프링] 06. JdbcTemplate - SimpleJdbcInsert & 기능 정리 (0) 2024.01.09 - @Profile("test")