- [트러블 슈팅] 2개 이상의 데이터베이스 초기화 기능은 사용하지 말자2025년 03월 22일 00시 40분 50초에 업로드 된 글입니다.작성자: do_hyuk
첫 번째 문제 발생
flyway로 DB 스키마 변경하는 테스트를 로컬에서 마치고, 개발 서버에 적용을 했을 때 발생한 오류이다.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]:Failed to initialize dependency 'flyway' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'flyway' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Circular depends-on relationship between 'flyway' and 'entityManagerFactory'
이 오류의 원인은 'flyway'와 'entityManagerFactory' 빈 사이의 순환 의존성 관계라고 한다.
Spring 애플리케이션 컨텍스트가 초기화되는 동안 발생한 이 문제는 두 빈이 서로를 참조하고 있어 Spring이 어느 것을 먼저 생성해야 할지 결정하지 못하는 상황을 나타내는 것이라는데 좀 더 알아봐야겠다.
일단 flyway를 dev에 적용하다 발생한 오류이기 때문에 로컬 설정과 차이점이 무엇인지 생각을 해보았다.
현재 local에는 없고 dev에는 있는 설정은 data.sql을 위한 defer-datasource-initialization 설정과 sql.init.mode 가 있다.
이 두 옵션에 대해 먼저 알아보았다.
defer-datasource-initialization
Hibernate가 데이터베이스 스키마를 생성한 후에 data.sql과 같은 초기화 스크립트를 실행하도록 지연시키는 역할이다.
sql.init.mode
data.sql 같은 DB 초기화는 in-memory db를 사용할 때만 가능하기 때문에, MySQL 같은 다른 데이버테이스에서도 적용하고 싶다면 spring.sql.init.mode = always와 같이 설정해야 한다.
그렇다면 해당 옵션과 flyway와 충돌이 날 무언가가 있는걸까? 했을 때 data.sql도 DB를 초기화 하는 기능이고 flyway DB에 접근하기 때문에 이 부분에서 충돌이 날 것이라 예상이 된다.
찾아보니 defer-datasource-initialization 옵션을 true로 설정할 경우 Flyway가 실행되기 전에 data.sql이 실행될거라 생각했지만, 이 설정은 Hibernate와 data.sql 간의 순서를 조정할 뿐 Flyway와는 조화를 이루지 않는다. 또한 Spring Boot 공식 홈페이지에서도 여러 데이터베이스 초기화 기술을 사용하는 것을 권장하지 않는다 되어있다.
문제 해결
jpa: show_sql: true hibernate: ddl-auto: validate defer-datasource-initialization: false # Flyway가 먼저 마이그레이션을 적용한 후에 JPA 실행
data.sql로 서버 실행 시 테스터 100명을 삽입했었지만 해당 기능의 필요성보다 flyway가 더욱 중요하기 때문에 data.sql과 관련 옵션은 삭제해주었다.
이 후에 서버 재실행시 테스터가 필요한 경우에는 수동으로 추가해야겠다..
두 번째 문제 발생
이제 제대로 적용될 줄 알았지만 V2.1까지만 성공하고 V2.2에서 실패하게 되었다.
오류 메시지는 다음과 같다.
버전 2.2 실패 원인 Member 테이블이 존재하지 않는다? 하지만 개발 서버의 DB를 보니 member 테이블이 제대로 있는 것을 확인하였다.
혹시나 Member와 member 대소문자의 차이로 인해 발생하나 싶어서 수정 후 다시 적용해보았다.
???...
V2.2__~.sql 파일의 Member를 member로 수정해주니 제대로 적용이 되었다.
로컬에서는 Member로 되어있는 스크립트가 제대로 적용됐으면서 왜 개발서버에는 안되었는지는 의문이다..
같은 mysql이지만 차이점이라면 dev 환경은 docker 내부에 mysql이 존재한다는 것 하나이다.
애초에 테이블 이름이 소문자인데 대문자로 작성한 나의 잘못이기에 따로 차이가 발생한 이유는 찾지 않겠다.
'포트폴리오 > AutoReview' 카테고리의 다른 글
[트러블 슈팅] 개발 서버와 배포 서버 사이에 DB 불일치 해결 (0) 2025.03.31 Join 연산 무조건 피해야 하나? (0) 2025.03.24 Flyway_Schema_History 테이블 자동 복구하기 (0) 2025.03.20 배포된 데이터베이스의 스키마를 변경해보자(2) (0) 2025.03.15 배포된 데이터베이스의 스키마를 변경해보자(1) (0) 2025.03.11 댓글