TroubleShooting SpringBoot와 data.sql 충돌

결론

해결 방안을 얻고 싶은 분은 이 부분만 참고하시면 됩니다.

Spring Boot 2.5 버전 이상에서 h2 DB를 통한 테스트를 실행할 때,

1. SQL의 Column은 `(grave accent)로 감싸고, Value는 '(single quote)로 감쌌는지 확인

2. yml파일에 spring:jpa:defer-datasource-initialization: true 추가하기


발단

1. Spring Boot에서 sql파일을 생성하고, JPA 연동을 통해 데이터가 잘 로드되는지 간단한 테스트를 하기위해 프로젝트를 생성했다.

build.gradle 확인하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
plugins {
id 'org.springframework.boot' version '2.5.6'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}

group = 'com.inwoo.jpa'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
useJUnitPlatform()
}

2. main 폴더 하위에 JpaRepository를 상속받은 repo를 생성하고, test폴더 하위 resource 폴더 내에 data.sql 파일을 생성하였다.

Primary Key인 id 증가를 위해 call next value for hibernate_sequence; 코드를 추가해주었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
call next value for hibernate_sequence;
insert into user ('id', 'name', 'email', 'created_at', 'updated_at') values (1, 'INWOO', 'INWOO@NAVER.COM', now(), now());

call next value for hibernate_sequence;
insert into user ('id', 'name', 'email', 'created_at', 'updated_at') values (2, 'DENNIS', 'DENNIS@NAVER.COM', now(), now());

call next value for hibernate_sequence;
insert into user ('id', 'name', 'email', 'created_at', 'updated_at') values (3, 'SOPHIA', 'SOPHIA@GOOGLE.COM', now(), now());

call next value for hibernate_sequence;
insert into user ('id', 'name', 'email', 'created_at', 'updated_at') values (4, 'JAMES', 'JAMES@GMAIL.COM', now(), now());

call next value for hibernate_sequence;
insert into user ('id', 'name', 'email', 'created_at', 'updated_at') values (5, 'INWOO', 'inwoo@gmail.com', now(), now());

3. Test 코드에 repo를 DI한 후 crud 테스트를 진행하였다.


결과

BeanCreationException 발생

Bean Definition에 있는 bean을 생성하려할 때 BeanFactory에서 발생하는 예외입니다.

Error creating bean with name ‘dataSourceScriptDatabaseInitializer’ defined in class path resource [path]:

class path에 위치한 Database와 관련된 bean을 생성할 때 오류가 발생하였다.

Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException:

init 메서드를 호출 실패; ScriptStatementFailedException 예외도 따라서 발생되었다.

Failed to execute SQL script statement #2 of URL [filepath]:

path의 2번째에 위치한 script 실행이 실패하였다.


해결 시도

Controller 테스트는 통과하였고, 생성한 repository는 상속만 받았다.

테스트 코드에서 Autowired를 해주었고, 단순 메서드만 호출하였기 때문에 오류는 없었다.

Exception을 참고하여 Spring 자체에서 Bean 자체를 생성하지 못하고 있다는 걸 깨달았다.

SpringBoot 2.5 버전이 나올 때 어떤 이슈가 있었는지 찾아보기 위해 Release Notes를 확인해보았다.
Release Notes


이슈

schema.sql and data.sql Files

With Spring Boot 2.5.1 and above, the new SQL initialization properties support detection of embedded datasources for JDBC and R2DBC.

Spring Boot 2.5.1버전 이상부터 새로운 SQL initialization 속성이 JDBC와 R2DBC의 source를 찾아줍니다.

By default, SQL database initialization is only performed when using an embedded in-memory database.

Default로는 in-memory db를 사용할 때만 초기화가 동작합니다.

To always initialize a SQL database, irrespective of its type, set spring.sql.init.mode to always.

모든 Type의 SQL DB를 초기화를 적용하기 위해 spring.sql.init.mode 값을 always로 바꿔주어야합니다.

application.yml 파일의 설정을 아무리 바꿔주어도 해결되지 않았다.

그래서 build.gradle 파일을 확인해보았는데, dependencytest가 제대로 build 되지 않고 있었다.

vi $HOME/.zsh를 통해 jdk 버전을 확인해보았는데 jdk가 16버전이었고, 이는 gradle과 아직 호환이 되지 않는 버전이었다.

그래도 실행이 되지 않았다..

해결

sql에 syntax 오류가 있는지 확인해봤는데 자세히 보니 column(grave accent)로 닫아주고 value'(Single Quote)로 닫아주었다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

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, 'inwoo', 'inwoo@slowcampus.com', now(), now());

call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`,`updated_at`) values (5, 'inwoo', 'inwoo@google.com', now(), now());

TroubleShooting SpringBoot와 data.sql 충돌

http://inwoo.github.io/11/03/jpaTroubleShooting/

Author

Inwoo Jeong

Posted on

2021-11-03

Updated on

2021-11-03

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

댓글