이전 글에서는 새로 만든 컨테이너에서 호스트에 설치된 MySQL까지 성공적으로 연결을 확인했다. 그래서 자신 있게 애플리케이션을 다시 배포했지만…
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] due to: Unable to determine Dialect without JDBC metadata (please set 'jakarta.persistence.jdbc.url' for common cases or 'hibernate.dialect' when a custom Dialect implementation must be provided)
계속해서 db 연결에 실패하는 모습을 찾아볼 수 있었다. 🥹
logging:
level:
org.springframework.jdbc.datasource: DEBUG
org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl: DEBUG
com.zaxxer.hikari.pool.HikariPool: DEBUG
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
조금 더 자세한 로그를 보기 위해 yml 파일에 다음을 추가해주었다.
| 항목 | 설명 | 로그 레벨 |
|---|---|---|
org.springframework.jdbc.datasource | 스프링 JDBC 데이터소스 관련 동작 (커넥션 획득, 반환 등) 로그 | DEBUG |
org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl | 하이버네이트가 JDBC 커넥션을 드라이버 매니저로부터 얻는 과정 | DEBUG |
com.zaxxer.hikari.pool.HikariPool | HikariCP 커넥션 풀의 상태 및 커넥션 생성, 반환, 종료 관련 로그 | DEBUG |
org.hibernate.SQL | 하이버네이트가 실행하는 SQL 쿼리 로그 | DEBUG |
org.hibernate.type.descriptor.sql.BasicBinder | 하이버네이트의 SQL 쿼리 파라미터 바인딩 과정 (매우 상세 로그) | TRACE |
| 로그 레벨 | 설명 |
|---|---|
| TRACE | 가장 상세한 로그. 함수 호출, 변수 상태 등 세밀한 정보 포함 |
| DEBUG | 개발 및 디버깅 목적의 상세 정보 |
| INFO | 일반적인 실행 정보 (기본 로그 레벨) |
| WARN | 주의가 필요한 경고 메시지 |
| ERROR | 심각한 오류 및 예외 메시지 |
로그 레벨을 설정한 후 로그를 보니 아래와 같은 에러가 발생한 것을 볼 수 있었다.
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed 에러는 MySQL 8.0 이상에서 기본 인증 방법(caching_sha2_password)으로 접속 시, 드라이버가 서버의 공개키를 받아오지 못해 발생하는 보안 관련 예외이다.
spring:
datasource:
url: jdbc:mysql://172.17.0.1:3306/<db명>?serverTimezone=UTC&useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true
위와 같이 allowPublicKeyRetrieval=true 옵션을 추가해주면 MySQL 서버의 공개 키를 안전하게 받아올 수 있어 보안 오류를 우회할 수 있다.
ALTER USER '<계정명>'@'%' IDENTIFIED WITH mysql_native_password BY '<비밀번호>';
FLUSH PRIVILEGES;
대부분의 경우 1번 설정만으로 문제가 해결되지만, 내 경우에는 추가로 인증 방식을 변경해야 했다. 따라서 mysql 사용자의 인증 방법을 mysql_native_password로 변경하였더니 드디어 연결에 성공할 수 있었다. 이렇게 하면 1번처럼 JDBC URL에 allowPublicKeyRetrieval=true을 추가할 필요가 없다. (mysql_native_password는 공개키 기반 인증이 아니기 때문에 드라이버가 공개키 요청을 하지 않아서 allowPublicKeyRetrieval=true 옵션을 설정해도 무시된다.)
이렇게 JDBC URL 설정과 사용자 인증 방식을 함께 조정해 주면서, 드디어 애플리케이션에서 호스트 MySQL에 정상적으로 연결될 수 있었다.
yml 로깅 설정
https://docs.spring.io/spring-boot/reference/features/logging.html
Public Key Retrieval
https://shiba-holic.tistory.com/103