티스토리 뷰

반응형

Spring Data JPA를 통해 MySQL DB 연결을 설정하는 방법에 대해 정리하는 글입니다.

 

1. 환경설정

build.gradle.kts

// Spring Data JPA 스타터 추가
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
// MySQL Connector 추가
runtimeOnly("mysql:mysql-connector-java:8.0.22")

연결할 DB가 MySQL이 아니라면 연결할 DB에 해당하는 Connector를 추가해주면 됩니다.

 

 

2. DB 프로퍼티 설정

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: "jdbc:mysql://localhost:3306/Memo?autoReconnect=true&useUnicode=true&serverTimezone=Asia/Seoul"
    username: root
    password: 1234
  jpa:
    database: mysql
    database-platform: org.hibernate.dialect.MySQL8Dialect
    properties:
      hibernate:
        storage_engine: innodb
        format_sql: true
        use_sql_comments: true
    hibernate:
      ddl-auto: none
    open-in-view: false
    show_sql: true

  logging.level:
    org.hibernate.SQL: debug

출처: https://spring.io/guides/gs/accessing-data-mysql/

 

프로퍼티 옵션에 대해서는 여러 블로그에서 자세히 설명하고 있으므로 간단하게 몇개만 살펴보겠습니다.

  • hibernate.ddl-auto
    • 옵션 종류: create, create-drop, update, validate, none
    • create: 기존 테이블 삭제 후 다시 생성
    • create-drop: 종료시점에 테이블 DROP 후 시작시점에 다시 생성
    • update: 기존 테이블과 비교후 변경분만 반영
    • validate: 엔티티와 테이블이 정상 매핑되었는지 확인
    • none: ddl을 사용하지 않음
    • ddl-auto 옵션을 create, create-drop을 사용하게 되면 시점은 다르지만 기존테이블을 삭제후 다시 생성하기 때문에 서버를 매번 시작할때마다 기존 데이터가 전부 날아가게 됩니다.
    • 로컬 환경에서만 create 옵션을 사용하고 그 외의 환경에서는 validate or none 옵션을 사용하는걸 추천합니다.
  • open-in-view
    • Open-In-View 또는 Open-Session-In-View 라고 많이 불리는데 관례상 OSIV라고 말합니다.
    • JPA에서는 OEIV(Open EntityManager In View), 하이버네이트에선 OSIV(Open Session Iv View)라고 각자 부르는 명칭만 다를뿐 의미는 같다.
    • 결론만 먼저 말하자면 항상 false 값으로 설정하는것을 추천드립니다
    • 기본 값인 True로 설정하게 되면 영속성 컨텍스트 범위가 넓게 설정되고 성능에도 영향이 있습니다.
    • 자세한 내용은 여기를 참고해보시면 좋을거 같습니다.

 

MySQL Connector를 8.x 대를 사용하게 되면 아래와 같은 에러가 발생하는 경우가 있습니다.

첫번째 줄 에러 메시지 내용은 아래와 같습니다.

Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: 
	The server time zone value 'KST' is unrecognized or represents more than one time zone. 
	You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) 
	to use a more specific time zone value if you want to utilize time zone support.

에러 내용을 보면 time zone 값을 설정해주라는 내용을 확인 할 수 있습니다.

MySQL Connector가 5.x 대에서는 timezone 값을 시스템 기본값을 사용하는데 반면에 8버전 부터는 timezone 값을 명시해주도록 변경 되었다고 합니다.

따라서 JDBC URL 부분에 serverTimezone=Asia/Seoul 옵션을 추가 해주면 에러를 해결할 수 있습니다.

출처: https://www.lesstif.com/dbms/mysql-jdbc-the-server-time-zone-value-kst-is-unrecognized-or-represents-more-than-one-time-zone-100204548.html

 

 

3. Custom DataSource 설정

보통의 경우에는 2번까지 설정 만으로도 사용이 가능합니다.

만약 DB의 username, password 값을 yaml 파일에 작성해 두는 것이 아니라 외부로 부터 받아 오는 경우가 있을 수 있습니다.

예를 들어 민감정보를 보호하기 위해 어플리케이션이 구동할때 AWS SecretsManager or Vault를 통해 DB 사용자 정보를 받아와 DataSource를 설정할 수 있습니다.

 

이러한 경우를 위해 DataSource를 JavaConfig 방식으로 설정하는 방법을 알아보겠습니다.

 

3.1 JavaConfig 방식으로 변경

먼저 기존 Yaml 파일의 환경설정값을 유지한채 JavaConfig 방식으로 변경해보겠습니다.

DataSourceConfiguration.kt

@Configuration
class DataSourceConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    fun dataSource(): DataSource =
        DataSourceBuilder.create().build()
}

@ConfigurationProperties 는 yaml 파일에 있는 설정을 오토 바인딩 해주는 어노테이션입니다.

prefix를 spring.datasource 로 지정해 놓았기 때문에 자동으로 spring.datasource 설정 아래 항목들을 읽어와서 

DataSource를 생성해줍니다.

 

그러나 위와 같이 작성하게 되면 아래의 에러 코드를 만나게 될것입니다.

java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.

 

먼저 해결 방법은 간단합니다. yaml 파일에 있는 spring.datasource.url 항목을 jdbcUrl로 변경해주면 됩니다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    // url -> jdbcUrl
    jdbcUrl: "jdbc:mysql://localhost:3306/Memo?autoReconnect=true&useUnicode=true&serverTimezone=Asia/Seoul"
    username: root
    password: 1234

 

🤔  왜 jdbcUrl로 설정을 변경해 주어야 할까요??

springboot는 2.0 이전에는 tomcat-jdbc를 사용하였으나, 2.0 이후부터는 HikariCP를 기본옵션으로 채택하고 있습니다.

스프링 어플리케이션을 실행하실경우 로그에서도 hikari가 기본적으로 적용 되어 있는것을 확인 할 수 있습니다.

 

 

HikariCP의 문서를 살펴보면 Configuration 값에서 jdbcUrl 옵션을 사용하는 것을 확인 할 수 있습니다.

실제로 환경설정시에 url 값을 보면 hikari만 jdbc-url 값을 사용하는 것을 확인 할 수 있습니다.

 

hikari.jdbc-url 설정

hikari.jdbc-url 로 설정을 해주면 되는거 아닌가? 라고 생각하실 수도 있을것 같습니다.

결론부터 말씀 드리면 맞습니다. 아래와 같이 hikari 설정으로 맞춰서 변경해 주어도 가능합니다.

spring:
  datasource:
    hikari:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: "jdbc:mysql://localhost:3306/Memo?autoReconnect=true&useUnicode=true&serverTimezone=Asia/Seoul"
      username: root
      password: 1234
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
fun dataSource(): DataSource =
    DataSourceBuilder.create().build()

Custom DataSource 설정을 하시는 경우라면 jdbcUrl로 설정하셔도 hikari.jdbc-url로 설정하셔도 아무런 상관이 없습니다.

 

다만, 기존 1,2번 방식으로 설정하시는 경우라면 굳이 hikari 설정에 맞춰 변경 할 필요는 없지 않을까 생각해봅니다.

 

현재 spring은 datasource.url 설정을 입력하면 자동으로 hikari 설정으로 변환해주어 적용을 해주고 있고, 이러한 부분은 추후 hikariCP가 아닌 다른 connection으로 변경이 되더라도 spring이 변경된 부분에 맞춰 자동으로 적용을 해줄테니 사용자인 저희가 신경을 쓰지 않아도 됩니다.

 

오히려 hikari에 종속적이게 설정을 해준다면 이전에 tomcat -> hikari로 변경된것 처럼 connection이 변경될 시 관련된 모든 부분을 변경해 주어야 하는 번거로움이 생기게 됩니다.

 

3.2. username, password 외부 입력

이제 DB설정중 username, password 부분을 외부로 부터 받는다고 가정해보겠습니다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbcUrl: "jdbc:mysql://localhost:3306/Memo?autoReconnect=true&useUnicode=true&serverTimezone=Asia/Seoul"
    // username: root (제거)
    // password: 1234 (제거)

 

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
fun dataSource(): DataSource {
    val username = "root"
    val password = "1234"
    return DataSourceBuilder.create()
        .username(username)
        .password(password)
        .build()
}

설정 방법은 간단합니다. yml파일에 있는 username, password 항목은 필요가 없으니 삭제하고, DataSourceBuilder로 create시에 직접 입력해주면 됩니다.

 

다만, 여기서 한가지 주의해야 하는 부분이 있습니다.

아래 글은 여기에서 가져온 일부분 입니다.

https://www.baeldung.com/spring-boot-configure-data-source-programmatic

내용을 읽어보면 application.properties 파일과 같은 외부 소스에 정의된 속성으로 override(재정의) 된다는 부분인데요.

 

간단하게 테스트를 통해서 직접 확인해 보겠습니다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbcUrl: "jdbc:mysql://localhost:3306/Memo?autoReconnect=true&useUnicode=true&serverTimezone=Asia/Seoul"
    username: external
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
fun dataSource(): DataSource {
    val username = "internal"
    val password = "1234"
    return DataSourceBuilder.create()
        .username(username)
        .password(password)
        .build()
}

properties 파일에서는 username을 "external"로 dataSource 빈 생성시에는 username을 "internal" 로 설정하였습니다.

 

이후에 어플리케이션을 실행시켜보면 username이 "external" 로 설정된걸 확인 할 수 있습니다.

만약 application.yml 과 java config 방식 두가지를 동시에 사용한다면 외부 소스(application.yml에 더 우선순위가 있으므로 해당 부분을 고려해서 설정 하시면 될것 같습니다!

 

 

참고자료

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.java-config

https://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함