본문 바로가기
  • 개발하는 곰돌이
Development/JPA

[JPA] hibernate의 ddl-auto 속성의 종류와 주의해야할 점

by 개발하는 곰돌이 2023. 3. 14.

목차

    개요

    JPA의 구현체 중 하나인 하이버네이트는 다양한 기능을 제공하는데 그 중 엔티티만 등록해놓으면 DDL(Data Definition Language)을 자동으로 작성하여 테이블을 생성하거나 수정해주는 ddl-auto라는 설정이 있다. JPA에 대해 아는 것이 거의 없던 처음에는 DDL을 자동으로 작성해주는 아주 편리한 기능이라고만 생각했는데, JPA를 배워가면서 마냥 편리한 기능이 아니라 잘못 다루면 돌이킬 수 없는 결과를 가져오는 아주 위험한(?) 기능이라는 것을 느끼게 되었다.

     

    이 포스트에서는 JPA 하이버네이트에서 제공하는 ddl-auto의 종류와 기능, 그리고 주의 사항에 대해서 정리하려고 한다.

    ddl-auto 속성의 종류

    ddl-auto에는 아래와 같이 5가지 종류의 속성이 있다.

    • create
    • create-drop
    • update
    • validate
    • none(default)

    create

    create는 단어 그대로 엔티티로 등록된 클래스와 매핑되는 테이블을 자동으로 생성(create)해준다. 이 과정에서 기존에 해당 클래스와 매핑되는 테이블이 존재한다면 기존 테이블을 삭제(drop)하고 테이블을 생성한다.

     

    create 옵션을 사용하면 아래와 같은 DDL이 자동으로 작성되어 DB에 반영된다.

    ddl-auto가 create일 때 생성되는 DDL

    create-drop

    create-dropcreate와 비슷하게 엔티티로 등록된 클래스와 매핑되는 테이블이 존재한다면 기존 테이블을 삭제하고 자동으로 테이블을 생성해주는 것은 똑같지만, 애플리케이션이 종료될 때 테이블을 삭제한다는 차이가 있다.

     

    create-drop 옵션을 사용하면 아래와 같이 애플리케이션이 시작될 땐 create와 동일한 DDL이 작성되지만, 애플리케이션이 종료될 때 테이블을 삭제하게 된다.

    애플리케이션 실행 시 create 쿼리가 작성된다.
    애플리케이션 종료 시 drop 쿼리가 작성된다.

    update

    update는 엔티티로 등록된 클래스와 매핑되는 테이블이 없으면 새로 생성하는 것은 create와 동일하지만 기존 테이블이 존재한다면 위의 두 경우와 달리 테이블의 컬럼을 변경하게 된다.

     

    하지만, 일반적으로 생각하는 update와는 달리 모든 변경사항을 반영하는 것이 아니다. 기존에 존재하는 컬럼의 속성(nullable, 크기, 데이터 타입 등)은 건드리지 않고, 새로운 컬럼이 추가되는 변경사항만 반영한다. 가령, 어떠한 엔티티 클래스의 String 필드를 Int로 변경하더라도 해당 엔티티에 매핑되는 테이블의 해당 컬럼은 숫자타입으로 바뀌지 않고 문자열 타입으로 유지된다.

    update 속성은 테이블이 존재하지 않으면 새로운 테이블을 생성한다.
    기존 테이블이 존재하고 엔티티의 필드가 추가되면 테이블에 추가된 필드에 해당하는 컬럼을 추가한다.

    validate

    validate는 다른 속성들과는 다르게 DDL을 작성하여 테이블을 생성하거나 수정하지 않고, 엔티티 클래스와 테이블이 정상적으로 매핑되는지만 검사한다. 만약 테이블이 아예 존재하지 않거나, 테이블에 엔티티의 필드에 매핑되는 컬럼이 존재하지 않으면 예외를 발생시키면서 애플리케이션을 종료한다.

     

    이 경우도 update와 비슷하게 엔티티 클래스의 필드가 매핑되는 테이블에 모두 존재하기만 한다면, 테이블의 컬럼이 더 많더라도 아무 일도 일어나지 않는다.

    엔티티 클래스와 테이블이 매핑되지 않으면 예외를 발생시키면서 애플리케이션이 종료된다.

    none(default)

    none은 사실 속성이 존재하는 것이 아니라 위의 4가지 경우를 제외한 모든 경우에 해당한다.(다만 스프링부트의 경우에는 none이라고 명시하거나 아예 ddl-auto 속성을 명시하지 않아야 한다.) 이 경우에는 아무 일도 일어나지 않는다.

    ddl-auto 속성을 사용할 때 주의사항

    유튜브 개발바닥 채널 호돌맨님의 운영DB 테이블 날리신 썰

    이상의 ddl-auto 속성들은 얼핏 보기엔 굉장히 편리해보이지만 validatenone을 제외한 속성은 운영 DB에는 절대!!! 사용하면 안된다. update라면 그나마 낫지만, createcreate-drop으로 설정한 채로 운영 DB에 연결하여 애플리케이션을 실행해버리면 운영 DB의 테이블이 몽땅 삭제되는 대참사가 일어나게 된다.

     

    update라고 하더라도 문제가 될 수 있는 것이, 만약 update로 인해 새로 추가된 컬럼이 not null이라면 해당 변경사항이 반영되지 않은 버전을 배포하게 되었을 때 테이블에 데이터가 INSERT 되지 않을 수 있다.

     

    따라서, 영한님의 JPA 강의에서는 아래와 같이 이 속성을 주의해서 사용할 것을 강조하고 있다. 또한 DDL을 날리는 것은 JPA에서 자동으로 작성해 주더라도 결국엔 사람의 손을 거쳐야 한다고 한다.

    • 개발 초기 단계 또는 로컬에서 테스트 : create 또는 update
    • 테스트 서버 : update 또는 validate
    • 스테이징 및 운영 서버 : validate 또는 none

    스프링부트 프로젝트에서 다중 프로파일 사용 시 추가 주의사항

    다중 프로파일을 사용하여 스프링부트 프로젝트의 속성을 관리하고 있다면 운영 프로파일의 ddl-auto 속성은 반드시 validate나 none으로 명시하거나, 공통 속성에 작성하지 않고 각 프로파일의 속성에 작성해야한다. [Spring Boot] 다중 Profile을 이용하여 환경에 따라 다른 설정 적용하기에서 언급했듯이 다중 프로파일을 사용하게 되면 해당 프로파일에 설정하지 않은 속성은 공통 속성에서 가져오게 된다.

     

    위 영상의 뒷부분에도 나와있지만, 사건이 터진 원인이 공통 속성에 ddl-autocreate로 설정했는데 운영용 프로파일에서는 설정을 해놓지 않았기 때문에 공통 속성의 create를 가져와서 발생한 것이라고 한다.

    결론

    ddl-auto 속성은 테스트 환경에서는 분명히 편리한 기능이 맞지만 운영 서버에서는 최소한의 검증만을 위해서 사용하거나, 아예 사용하지 않아야 한다. 호돌맨님의 사례도 매일 DB를 백업하고 있었기에 금방 복구할 수 있었던 것이고, DB를 백업하지 않거나 백업 주기가 길었다면 굉장한 참사가 발생했을지도 모를 일이라고 생각한다.

    댓글