1. 문제 발생
온라인 강의를 듣는 중, data.sql을 만들어서 기초 데이터를 넣는 부분이 있었다.
같은 소스를 실행했는데, 문제가 발생하여 데이터가 입력되지 않고 에러가 발생했다.
2. 원인 파악
프로젝트 구성 및 테스트 코드
data.sql
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (1, 'martin', 'martin@fastcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (2, 'dennis', 'dennis@fastcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (3, 'sophia', 'sophia@slowcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (4, 'james', 'james@slowcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (5, 'martin', 'martin@another.com', now(), now());
첫번째, 실행해 본 결과 -> 에러 발생
아래와 같이 HIBERNATE_SEQUENCE 가 문제인 듯 싶어, 'call next value for hibernate_sequence;' 부분을 주석 처리
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of URL [file:/C:/Users/Sim/Desktop/folder/develop/_%ec%b4%88%ea%b2%a9%ec%9e%90%20%ea%b0%95%ec%9d%98/Part4/bookmanager/build/resources/test/data.sql]: call next value for hibernate_sequence; nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Sequence "HIBERNATE_SEQUENCE" not found; SQL statement: call next value for hibernate_sequence [90036-200]
두번째, 실행해 본 결과
아래와 같이 USER 테이블이 생성되지 않았다하여 schema.sql도 생성
-> schema.sql을 통해 create table을 했지만 데이터가 생성되지 않음.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of URL [file:/C:/Users/Sim/Desktop/folder/develop/_%ec%b4%88%ea%b2%a9%ec%9e%90%20%ea%b0%95%ec%9d%98/Part4/bookmanager/build/resources/test/data.sql]: insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (1, 'martin', 'martin@fastcampus.com', now(), now()); nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USER" not found; SQL statement: insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (1, 'martin', 'martin@fastcampus.com', now(), now()) [42102-200]
3. 해결 방법
구글링을 하여, 검색하던 중 한 블로그를 발견하였고 원인을 찾았다.
Hibernate and data.sql
By default, data.sql scripts are now run before Hibernate is initialized. This aligns the behavior of basic script-based initialization with that of Flyway and Liquibase. If you want to use data.sql to populate a schema created by Hibernate, set spring.jpa.defer-datasource-initialization to true. While mixing database initialization technologies is not recommended, this will also allow you to use a schema.sql script to build upon a Hibernate-created schema before it’s populated via data.sql.
Spring Boot 2.5버전 부터는 data.sql 실행하려면 2가지 방법이 있다.
- application.yml(또는 properties)에 spring.jpa.defer-datasource-initialization 옵션 값을 true로 추가
- schema.sql을 추가해서 hibernate 가 스키마를 생성하는 과정보다 먼저 실행되도록하여 해당 스키마에 data.sql을 채우도록하는 방법
(2번째 방법은 권장하지 않는 방법)
application.yml
spring:
h2:
console:
enabled: true
jpa:
defer-datasource-initialization: true
data.sql이 잘 실행되어, 테스트 코드가 정상적으로 완료됐다.
Mysql에서 data.sql 읽는 방법
- 스프링부트 2.4.x에선 spring.datasource.initialization.mode를 사용해서 data.sql, schema.sql을 실행
- 스프링부트 2.5.x에선 spring.datasource.initialization.mode가 depreated로 표시
- spring.sql.init.mode로 대체 sql관련 공통화 부분을 spring.sql로 따로 분리를 시킨게 요인 (spring2.5-release-note)
스프링부트 버전: 2.4.x
spring:
...
datasource:
url: jdbc:mysql://localhost:3306/book_manager
username: root
password: root
initialization-mode: always
스프링부트 버전: 2.5.x
spring:
...
datasource:
url: jdbc:mysql://localhost:3306/book_manager
username: root
password: root
sql:
init:
mode: always
참고 사이트: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes
'백엔드 > SpringBoot' 카테고리의 다른 글
[ SpringBoot + jsp + intellij ] jsp 사용을 위한 설정 (1) | 2022.04.30 |
---|---|
[ 스프링부트 / Spring Boot ] 트랜잭션 전파가 안되는 현상 (0) | 2021.08.08 |
[ 스프링부트 / Spring Boot ] Swagger 간단히 구현 (0) | 2021.07.11 |
[Spring Security + JWT + Swagger] 로그인 구현 - 1. 프로젝트 세팅 (0) | 2021.07.10 |
[ 스프링부트 / Spring Boot ] Interceptor (0) | 2021.06.26 |