application.yml 구성하기!

maketheworldwise·2022년 5월 11일
0


application.yml 구성하기!

설정이 반이다! 라는 말이 있듯이 application.yml 파일을 설정하는 것은 프로젝트에서도 큰 비중을 차지하는 영역이라고 생각한다.

참고로, 우리는 처음에 Raw Query 형태로 MyBatis로 진행하려 했으나, 익숙하지 않은 탓과 MyBatis보다 조금 더 트렌디한 기술을 접목하는 편이 성향상(?) 프로젝트 진행을 원활하게 할 수 있을거라 판단하여 JPA를 바로 도입하기로 결정했다. (그래도 MyBatis를 알아두는 편이 좋을 것 같아 나는 브랜치를 따로 파서 샘플 코드를 구현해 흐름 정도는 이해했다. 😤)

추가한 의존성에 대한 내용은 생략하고 application.yml에 구성한 내용을 위주로 정리해보자.

profile

실무에서는 보통 개발 환경을 분리하기 때문에 우리도 동일하게 분리했다. 생각한 개발 환경은 로컬, 개발 서버, 실섭 총 3가지를 생각했고, 프로젝트 초기이기에 로컬을 중점으로 구성을 시작했다.

spring:
  profiles:
    active: local

---

spring:
  profiles:
    active: dev

---

spring:
  profiles:
    active: prod 

처음에는 위와 같이 하나의 application.yml 파일로 구성했으나, 관리 차원에서 각 환경별로 분리시키는 의견이 있어 - 3개의 파일로 나누어 재구성했다. 프로젝트를 진행하면서는 로컬 환경에서 많이 작업할 것이기에 로컬 환경을 기본 profile로 설정했다.

# application.yml
spring:
  profiles:
    default: local
# application-dev.yml
spring:
  config:
    activate:
      on-profile: dev
# application-prod.yml
spring:
  config:
    activate:
      on-profile: prod

datasource

다음은 DB 설정이다. Yousinsa 프로젝트에 사용할 DB는 MySQL이다. (비밀번호의 경우에는 JVM 옵션으로 덮어씌워지는 내용이라 공개해도 무관하다고 판단하여 그대로 깃에 반영했다. 🙂)

spring:

  # (profile 설정 생략...)

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/yousinsa?useSSL=false&serverTimezone=UTC
    username: root
    password: password

추가적으로 같이 프로젝트를 진행하는 K님도 동일한 로컬 환경에서 개발을 할 수 있도록 Dockerfile을 구성해 추가해 놓았다. 로컬에서 작업하기 위한 환경이므로 비밀번호는 쉽게 구성해놓았다.

FROM mysql:8.0.29

ENV character-set-server utf8mb4
ENV collation-server utf8mb4_general_ci
ENV default-character-set utf8mb4
ENV default-collation utf8mb4_general_ci

ENV MYSQL_DATABASE yousinsa
ENV MYSQL_ROOT_PASSWORD password

EXPOSE 3306

# docker build -t yousinsa:latest .
# docker run  -d -p 3306:3306 --name yousinsa yousinsa:latest

jpa

jpa 설정을 구성하는 것은 생각했던 것보다 옵션이 많아 구성하는데 까다로웠다. 일단 구성한 내용은 다음과 같다.

spring:
  
  # (profile 설정 생략...)
  # (datasource 생략...)

  sql:
    init:
      mode: never

  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
      use-new-id-generator-mappings: false
    show-sql: true
    properties:
      hibernate:
        format_sql: true
      dialect: org.hibernate.dialect.MySQL5InnoDBDialect

자 그럼 하나씩 뜯어보자.

open-in-view

open-in-view 옵션은 open-session-in-view 또는 open-entitymanager-in-view 라고도 불린다. 이 옵션은 영속성 컨텍스트의 생존 범위를 지정하는 옵션이다.

이 옵션이 true(기본값)일 경우에는 영속성 컨텍스트가 트랜잭션 범위를 넘어선 레이어까지 살아있다는 의미다. 즉, 클라이언트에게 응답될 때 까지 영속성 컨텍스트가 살아있다는 의미다.

반대로 false일 경우에는 트랜잭션 종료하면서 영속성 컨텍스트 또한 닫히는 구조다.

내가 참고한 레퍼런스에서 정의하길, 👇

  • true : 사용자에게 응답 또는 view가 렌더링 될 때까지 영속성 컨텍스트를 유지
  • false : 트랜잭션이 끝나면 영속성 컨텍스트도 닫힘

영속성 컨텍스트를 유지하고 있다는 의미는 DB Connection을 계속 가지고 있다는 의미이기에 실시간 트래픽이 중요한 애플리케이션에서는 DB Connection이 모자랄 수 있으므로, 성능이 중요하다면 false로 설정하는 편이 좋다.

hibernate

Hibernate는 도대체 무엇을 의미하는 걸까?

우선 JPA는 ORM 기술을 자바에서 사용하기 위한 인터페이스의 집합이다. 그리고 해당 인터페이스를 구현한 구현체로는 Hibernate, EclipseLink, DataNucleus가 있다.

Hibernate는 위에서 언급했듯, JPA의 구현체중 하나이며 내부적으로 JDBC API를 사용하고 있다.

JPA에 관련된 내용은 추후에 다시 정리할 예정이기에 간략하게 이해하고 넘어가자. 👏

hibernate.ddl-auto

sql.init.mode 옵션과 함께 봐야하는 옵션이다. 스프링 2.4 버전 이하에서는 spring.datasource.initialization-mode 로 설정했으니나, 2.5 버전 이상부터는 sql.init.mode로 변경되었다. 이 설정은 schema.sql과 data.sql 등의 스크립트를 동작할지 설정하는 옵션이다.

우리 프로젝트의 경우, schema.sql 파일과 data.sql 파일을 이용하여 초기 설정을 하기 때문에, 초기에 always로 sql.init.mode 옵션을 구성하고, 그 이후부터는 해당 스크립트를 다시 실행하지 않도록 never로 설정했다.

여기서 ddl-auto 옵션은 Hibernate에 의한 스키마 생성에 대한 옵션이다. 기본적으로는 우리가 작성한 스크립트가 먼저 동작하고 ddl-auto가 실행된다. 따라서 덮어씌워지지 않도록 해당 옵션에는 none으로 설정해두었다.

💡 ddl-auto 선 실행 후 스크립트 실행하도록 순서를 반대로 하려면 어떻게 할까?

ddl-auto가 먼저 실행하고자 한다면, spring.jpa.defer-datasource-initialization 옵션을 true로 설정하면 된다.

hibernate.naming

Hibernate Naming은 이름에서 대략적으로 유추할 수 있듯, 네이밍 전략을 설정하는 옵션이다. 네이밍 전략에도 논리(설명)으로 구성하는 방법과 물리(영문, 테이블명)로 구성하는 방법이 존재한다.

  • SpringImplicitNamingStrategy
  • SpringPhysicalNamingStrategy

(논리와 물리에 대한 내용은 DB를 공부하면서 나중에 추가적으로 정리하자! 😂)

그럼 어떤 전략이 있을까? 살펴보자.

  • SpringPhysicalNamingStrategy(Default) : CamelCase -> UnderScore
  • PhysicalNamingStrategyStandardImpl : 변수 이름을 그대로 사용

hibernate.use-new-id-generator-mappings

이 옵션은 자동 키 생성 전략을 결정할 때 사용한다.

DB 테이블의 기본키를 선정할 때는 자연키와 대체키라는 선택지가 존재한다. 자연키는 말 그대로 이메일이나 전화번호처럼 비즈니스적으로 의미있는 키를 의미하며, 대체키는 비즈니스와 관계없이 임의로 만들어진 키를 의미한다. 그리고 JPA에서는 테이블 대체키를 기본키로 자동 생성하는 기능을 @GeneratedValue 어노테이션으로 지원하고 있다. 이 어노테이션에서 지원하는 전략은 다음과 같다.

  • AUTO : JPA 구현체가 자동으로 생성 전략을 결정
  • IDENTITY : 기본키 생성을 DB에 위임 (ex. MySQL의 AUTO_INCREMENT)
  • SEQUENCE : DB의 특별한 오브젝트 시퀀스를 사용하여 기본키를 생성
  • TABLE : DB에 키 생성 전용 테이블을 만들고 기본키를 생성

여기서 가장 흔히 확인할 수 있는 전략은 AUTO와 IDENTITY다. 이번에 우리가 진행하는 프로젝트는 기본키 생성 전략을 DB에 위임하는 IDENTITY를 이용할 계획이다. 그리고 DB에 위임하는 방법을 이용하려면 JPA에서도 특별히 설정해주어야 하는 내용이 있는데, 그것이 바로 use-new-id-generator-mappings 옵션이다.

스프링 부트 1.5에서는 해당 옵션의 기본값이 false 였지만 2.0 부터는 true 로 변경되었기 때문에 사용시 주의해야한다. 1.5에서는 AUTO를 따라가지 않기 때문에 IDENTITY가 선택되었지만, 2.0부터는 Hibernate 5를 따라 TABLE이 선택된다.

따라서 우리는 이번 우리 프로젝트에 기본키 생성 전략으로 TABLE 을 따라가지 않고 IDENTITY를 따라가도록 하기 위해 false 로 구성했다.

show-sql

이 옵션은 Hibernate가 DB에 날리는 모든 쿼리를 보여주는 옵션이다. 해당 옵션은 local과 dev 환경에서만 돌아갈 수 있도록 설정해둘 예정이다.

properties.hibernate.format_sql

Hibernate를 사용할 때 더 가독성이 좋게 쿼리를 확인할 수 있도록 구성하는 옵션이다. 그 외에도 주석을 표시해주는 옵션인 use_sql_comments도 있다.

properties.dialect

DBMS의 종류는 굉장히 다양하다. 그리고 각 DBMS에서 사용하는 문법과 함수가 모두 동일하지 않다. 그리고 JPA는 특정 DB에 종속되어있지 않고 직접 SQL을 작성하고 실행하는 형태이다. 따라서 JPA가 DBMS에 맞는 쿼리를 생성할 수 있도록 구성할 때 사용하는 옵션이다.

logging

위에서 구성한 내용중 출력과 관련된 옵션은 모두 System.out로 보여준다. 하지만 이를 Logger를 이용하여 쿼리를 보여주도록 구성할 수 있다.

logging:
  level:
    org:
      hibernate:
        SQL: debug

추가적으로, type 옵션을 통해 어떤 값이 실려 전송되었는지 확인도 가능하다. 단, 값과 쿼리가 따로 보일 수 있기에 implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.8'의존성을 추가해야 한다.

logging:
  level:
    org:
      hibernate:
        SQL: debug
        type: trace

System.out으로 로그를 찍어내는 방식은 성능 저하의 원인이 될 수도 있다고 한다. 그리고 Logger는 최소한의 정보를 함께 찍어내기 때문에 Logger를 이용한 방법을 추천한다고 한다.

이 글의 레퍼런스

profile
세상을 현명하게 이끌어갈 나의 성장 일기 📓

0개의 댓글