개발공부/spring boot

🚨ERROR -org.springframework.jdbc.datasource.init.CannotReadScriptException: Cannot read SQL script from class path resource

기억지기 개발자 2024. 5. 27. 14:41

🏕️ 상황

@Sql("/insert-members.sql")
    @Test
    void getAllMembers() {
        // when
        List<Member> members = memberRepository.findAll();

        // then
        assertThat(members.size()).isEqualTo(3);
    }

프로젝트 구조.

  • 위에 있는 코드를 실행하려면 [insert-member.sql]를 읽어와야 하는데 해당 파일을 찾을 수가 없어서 오류가 계~~~~속 발생했다.

 


💦 과정

이 오류를 해결하기 위해서 3시간 넘게 쓰면서 아래에 있는 방법들 + α 를 시도해보았다.

 

1. 혹시 모르니 설정 파일에 전체 코드에 대한 로그 레벨을 설정해 보기

2. build.gradle 파일에서 sourceSets 블록에 src/test/resources 경로 지정하기

3. sql 파일의 이름 바꾸기 / 위치 바꾸기

4. 해당 경로가 맞는지 n차 확인

5. 절대경로로 표현해 보기

6. 설정 파일에 [spring.jpa.defer-datasource-initialization: true] 넣어보기

 


🗝️ 해결

위에 있는 방법을 아~무리해도 같은 오류 메시지가 계속 발생했다.

가끔가다가 다른 사람들도 resource 폴더를 인식을 못하는 경우가 있다길래 Settings에 들어가서 인식 여부를 확인해 봤는데,

잘 인식하고 있었다. 그러니 더더욱 막막했다.  검색해서 나오는 건 많이 해봤기 때문이다~~ 

 

아무리 시도를 해도 달라지지 않는 걸 보면 원래부터 or 오류를 해결하는 과정에서 프로젝트에 문제가 단단히 생겼다는 판단이 들어서 새로운 프로젝트를 생성해서 다시 프로젝트를 구성했다.

그랬더니 성공....!!! (오류를 해결하면서 꼭 알아가고 싶은 궁금증이 3개 생겼다.)

성공화면


 

💜 궁금증1 . @Sql을 사용해야 하는 이유

  1. 데이터베이스 초기화 및 설정:
    • 테스트를 실행할 때 데이터베이스를 특정 상태로 초기화해야 하는 경우가 있습니다. @Sql을 사용하면 테스트 실행 전에 SQL 스크립트를 실행하여 데이터베이스를 초기 상태로 설정할 수 있습니다.
    • 이는 특히 엔터프라이즈 애플리케이션에서 테스트 간에 데이터 일관성을 유지하는 데 유용합니다.
  2. 복잡한 데이터 시나리오:
    • JPA를 사용하여 데이터베이스 상태를 설정하는 것은 복잡한 데이터 시나리오에서는 번거롭고 시간이 많이 걸릴 수 있습니다. 복잡한 데이터 모델이나 관계를 설정해야 하는 경우 SQL 스크립트를 사용하는 것이 더 간단하고 명확할 수 있습니다.
    • @Sql을 사용하면 복잡한 데이터 시나리오를 간단한 SQL 쿼리로 설정할 수 있습니다.
  3. 데이터베이스 종속 테스트:
    • 특정 SQL 기능이나 데이터베이스의 동작을 테스트해야 할 때 @Sql을 사용하여 직접 SQL을 실행하고 테스트할 수 있습니다. 이는 JPA가 지원하지 않는 특정 데이터베이스 기능을 테스트하는 경우 유용합니다.
    • 예를 들어, 특정 데이터베이스 트리거나 스토어드 프로시저를 테스트해야 하는 경우 @Sql을 사용하여 이를 설정하고 테스트할 수 있습니다.
  4. 독립적이고 재현 가능한 테스트:
    • 테스트는 독립적이어야 하고, 어떤 순서로 실행되든 동일한 결과를 보장해야 합니다. @Sql을 사용하면 각 테스트 전에 데이터베이스를 동일한 상태로 초기화할 수 있으므로 테스트가 독립적이고 재현 가능하게 됩니다.
    • 이를 통해 테스트 간의 상호 의존성을 최소화할 수 있습니다.
  5. 테스트 데이터 관리의 편리성:
    • @Sql 파일을 사용하면 테스트 데이터를 외부 파일로 관리할 수 있으므로, 테스트 데이터를 수정하거나 재사용하기 쉽습니다.
    • 여러 테스트에서 동일한 데이터 초기화가 필요할 때, 동일한 @Sql 스크립트를 재사용할 수 있습니다.

데이터베이스를 초기 상태로 설정한다는 것은 ??

테스트를 실행하기 전에 데이터베이스를 특정한 상태로 만드는 것을 말합니다.
이렇게 하면 각 테스트가 동일한 시작 지점에서 시작하고, 이전 테스트가 다음 테스트에 영향을 주지 않게 됩니다.

 


💜 궁금증2 . sql 파일의 위치

.sql 파일은 꼭 resources 안에 있어야 한다는 사실을 알게 되었다.

Spring Boot에서는 @Sql 어노테이션을 사용하여 SQL 스크립트를 실행할 때, 해당 SQL 파일을 애플리케이션의 클래스패스(classpath)에서 찾는다. 보통 클래스패스는 src/main/resources 또는 src/test/resources디렉터리에 있는 파일들을 포함한다.

  • src/main/resources: 주로 애플리케이션이 실행될 때 필요한 리소스 파일을 포함한다. 예를 들어, 프로덕션 환경에서 사용할 SQL 스크립트나 설정 파일 등이 여기에 위치한다.
  • src/test/resources: 주로 테스트를 실행할 때 필요한 리소스 파일을 포함한다. 테스트용 SQL 스크립트나 테스트 설정 파일 등이 여기에 위치한다.

💜 궁금증3 . "spring.jpa.defer-datasource-initialization: true" 의 역할

문제 상황

Spring Boot 애플리케이션을 시작할 때, 보통 두 가지 일이 순서대로 일어난다. 

  1. 데이터베이스 초기화: SQL 스크립트를 실행해서 테이블을 만들거나 데이터를 넣는다.
  2. JPA 초기화: JPA가 엔터티를 보고 데이터베이스 테이블을 자동으로 만든다.

문제는 이 두 가지가 잘못된 순서로 실행되면, 예를 들어 데이터베이스 초기화가 JPA 초기화보다 먼저 실행되면, 데이터베이스 테이블이 아직 없어서 오류가 날 수 있다는 점이다.

해결책

spring.jpa.defer-datasource-initialization=true 설정을 사용하면, Spring Boot는 JPA가 먼저 데이터베이스 테이블을 만든 후에 SQL 스크립트를 실행한다. 이렇게 하면 데이터베이스 테이블이 준비된 상태에서 데이터를 넣을 수 있다.

 


 

👩🏻‍💻느낀 점

  • 오랫동안 한 가지 오류를 해결하려다 보니 그 과정에서 생기는 의문점이 많았고, 별의별 처음 알게 된 기능들이나 규칙들도 많아서 힘들지만 좋았다.
  • 공부를 하면 할수록 더 모르겠는 것이 스프링의 매력이라고 생각한다ㅎㅎ 절대 쉽게 가질 수 없는 :)
  • 원래도 얄팍한 실력이지만 더욱더 겸손한 마음으로 더 치열하고, 꼼꼼하게 공부하고 싶다는 생각이 들었다♥
  • 그리고 프로젝트를 새로 만들어서 하는 방법이 내 생각에는 그렇게 멋진..? 방법은 아니라는 생각이 드는데... 괜찮은 방법인지 모르겠다.