JPA hbm2ddl.auto="create"의 진짜 위험성 — 데이터가 ‘정상적으로’ 날아가는 순간들

2025-08-22 13:14:20

1) create가 위험한 “진짜” 순간 6가지

  1. 프로파일 스위치 실수

    • spring.profiles.active=dev 로 믿고 배포 → 실제로 prod가 떠도 application.yml 병합 우선순위 때문에 create가 적용될 수 있음.

  2. CI/CD에서 환경 변수 누락

    • 깃 액션/젠킨스에서 SPRING_PROFILES_ACTIVE 빠짐 → 기본 yml의 create가 적용, 스키마 드롭.

  3. 멀티 인스턴스 롤링 재시작

    • 인스턴스 A가 create로 드롭 → 인스턴스 B는 기존 커넥션 살아있다고 착각 → 운영 중간에 테이블 없어서 장애.

  4. 테스트를 운영 DB로 붙인 사고

    • 로컬 .env/Datasource URL 오타로 운영에 접속 → 통합테스트 시작과 동시에 create로 초기화.

  5. 마이그레이션 도구와 혼용

    • Flyway로 관리하다가 신입이 create 켠 채 배포 → Flyway 히스토리 테이블까지 날리고, 재적용 과정에서 실패.

  6. DB 권한이 과도하게 넓을 때

    • 운영 계정에 DROP/CREATE 권한이 열려있으면 방어막이 전혀 없음.

공통점: 경고 없이 “정상 동작”처럼 보이며 데이터가 사라진다는 것.


2) 안전한 운영 패턴 (추천 조합)

운영(Production)

스테이징/QA

개발(Local)

# application-prod.yml
spring:
  jpa:
    hibernate:
      ddl-auto: validate
  datasource:
    url: jdbc:postgresql://prod:5432/app
    username: app
    password: ****


3) 프로파일/환경 가드(막아두기)

(1) 실행 시 강제 차단 코드

@PostConstruct
public void forbidCreateInProd(@Value("${spring.jpa.hibernate.ddl-auto:none}") String ddlAuto,
                               @Value("${spring.profiles.active:}") String profile) {
    if ("prod".equals(profile) && ("create".equalsIgnoreCase(ddlAuto) || "create-drop".equalsIgnoreCase(ddlAuto))) {
        throw new IllegalStateException("PROD에서 hbm2ddl=create/create-drop 금지!");
    }
}

(2) 빌드 타임 실패(Gradle)

tasks.register("checkProdDdlAuto") {
    doLast {
        def prod = file("src/main/resources/application-prod.yml").text
        if (prod.contains("ddl-auto: create") || prod.contains("ddl-auto: create-drop")) {
            throw new GradleException("application-prod.yml 에서 ddl-auto=create 금지")
        }
    }
}
build.dependsOn("checkProdDdlAuto")

(3) 운영 계정 권한 축소 예시(PostgreSQL)

REVOKE CREATE, TEMP ON DATABASE app FROM app_user;
REVOKE ALL ON SCHEMA public FROM app_user;
GRANT USAGE ON SCHEMA public TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;


4) Flyway로 바꾸는 마이그레이션 절차(무중단 지향)

  1. 현행 스키마 스냅샷: pg_dump -s 등으로 구조만 덤프 → V1__baseline.sql.

  2. spring.jpa.hibernate.ddl-auto=validate 로 다운그레이드.

  3. 이후 변경은 V2__...sql, V3__...sql로 관리.

  4. 롤링 배포 시 forwards-only 전략(다운 마이그레이션은 별도 브랜치로 검증).

  5. 배포 전 Flyway info, migrate -dryRunOutput로 시뮬레이션.


5) “create가 꼭 필요”한 순간을 위한 격리법

@Container
static PostgreSQLContainer db = new PostgreSQLContainer<>("postgres:16");


6) 체크리스트 (포스팅 하단 붙이는 용)

7) persistence.xml/환경설정 관리 팁

  1. 버전관리에서 제외

    • persistence.xml, application-*.ymlDB 접속 정보/ddl-auto 옵션 포함된 파일.gitignore 또는 SVN exclude 처리.

    • 개발자별 로컬 환경에서만 관리하고, 공용 리포에는 샘플 템플릿(application-example.yml)만 두기.

  2. 환경변수/시크릿 매니저 사용

    • Spring Boot라면 spring.datasource.*spring.jpa.hibernate.ddl-auto 값을 OS 환경변수Vault/Secret Manager에서 주입.

    • 이렇게 하면 git pull → 곧바로 운영 날리는 사고 방지.

  3. CI/CD에서 안전가드

    • 배포 파이프라인에서 grep ddl-auto=create 같은 체크 넣고, 발견되면 빌드 실패.

    • 운영 배포 시 기본값 validate 강제.



“persistence.xml이나 yml 설정은 절대 버전관리툴에 올리지 말자.

대신 템플릿만 공유하고, 실제 값은 로컬·환경변수에서 관리해야 한다.

이 작은 습관 하나가 운영 DB를 지켜준다.”

목록
Facebook 이 댓글은 페이스북 로그인으로만 작성할 수 있어요.
Facebook으로 로그인
페이스북 공유 이 글을 페이스북에 공유하기