JPA hbm2ddl.auto="create"의 진짜 위험성 — 데이터가 ‘정상적으로’ 날아가는 순간들
| 2025-08-22 13:14:20 |
|---|
create는 애플리케이션 시작 시 스키마를 드롭하고 재생성한다.CI/CD, 프로파일/환경 변수 실수, 다중 인스턴스, Flyway/Liquibase와 혼용 시 무경고 데이터 증발이 발생한다.
운영은 마이그레이션 도구(Flyway/Liquibase) +
validate/none조합으로.개발은
update도 남용 금지. 테스트 컨테이너/임베디드 DB로 격리하자.
1) create가 위험한 “진짜” 순간 6가지
프로파일 스위치 실수
spring.profiles.active=dev로 믿고 배포 → 실제로 prod가 떠도application.yml병합 우선순위 때문에create가 적용될 수 있음.
CI/CD에서 환경 변수 누락
깃 액션/젠킨스에서
SPRING_PROFILES_ACTIVE빠짐 → 기본 yml의create가 적용, 스키마 드롭.
멀티 인스턴스 롤링 재시작
인스턴스 A가
create로 드롭 → 인스턴스 B는 기존 커넥션 살아있다고 착각 → 운영 중간에 테이블 없어서 장애.
테스트를 운영 DB로 붙인 사고
로컬
.env/Datasource URL 오타로 운영에 접속 → 통합테스트 시작과 동시에create로 초기화.
마이그레이션 도구와 혼용
Flyway로 관리하다가 신입이
create켠 채 배포 → Flyway 히스토리 테이블까지 날리고, 재적용 과정에서 실패.
DB 권한이 과도하게 넓을 때
운영 계정에
DROP/CREATE권한이 열려있으면 방어막이 전혀 없음.
공통점: 경고 없이 “정상 동작”처럼 보이며 데이터가 사라진다는 것.
2) 안전한 운영 패턴 (추천 조합)
운영(Production)
spring.jpa.hibernate.ddl-auto=validate또는none스키마 변경은 Flyway/Liquibase에만 맡긴다.
운영 DB 계정 권한 최소화(DDL 불가).
드라이런(마이그레이션 시뮬레이션) + 백업 자동화.
스테이징/QA
validate권장.스키마는 운영과 동일하게 마이그레이션 스크립트로만 갱신.
롤백 시나리오(다운 마이그레이션) 준비.
개발(Local)
빠른 실험은 가능하지만
update도 남용 주의.Testcontainers(PostgreSQL/MySQL)로 DB를 켜고 끈다 — 로컬 영속 DB와 분리.
# 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로 바꾸는 마이그레이션 절차(무중단 지향)
현행 스키마 스냅샷:
pg_dump -s등으로 구조만 덤프 →V1__baseline.sql.spring.jpa.hibernate.ddl-auto=validate로 다운그레이드.이후 변경은
V2__...sql,V3__...sql로 관리.롤링 배포 시 forwards-only 전략(다운 마이그레이션은 별도 브랜치로 검증).
배포 전 Flyway
info,migrate -dryRunOutput로 시뮬레이션.
5) “create가 꼭 필요”한 순간을 위한 격리법
테스트 컨테이너
@Container
static PostgreSQLContainer> db = new PostgreSQLContainer<>("postgres:16");
별도 프로파일:
local-reset같은 임시 프로파일에서만create허용, 기본은 항상validate.샌드박스 DB: 운영 VPC와 물리적으로 분리.
6) 체크리스트 (포스팅 하단 붙이는 용)
운영 프로파일에
ddl-auto=validate/none인가?운영 DB 계정 DDL 권한 제거됐는가?
Flyway/Liquibase로만 스키마 변경하는가?
배포 파이프라인에서 프로파일/환경 변수 검증하는가?
create/create-drop은 샌드박스에서만 가능한가?배포 전 백업·드라이런 자동화가 있는가?
7) persistence.xml/환경설정 관리 팁
버전관리에서 제외
persistence.xml,application-*.yml중 DB 접속 정보/ddl-auto 옵션 포함된 파일은.gitignore또는 SVN exclude 처리.개발자별 로컬 환경에서만 관리하고, 공용 리포에는 샘플 템플릿(
application-example.yml)만 두기.
환경변수/시크릿 매니저 사용
Spring Boot라면
spring.datasource.*와spring.jpa.hibernate.ddl-auto값을 OS 환경변수나 Vault/Secret Manager에서 주입.이렇게 하면
git pull→ 곧바로 운영 날리는 사고 방지.
CI/CD에서 안전가드
배포 파이프라인에서
grep ddl-auto=create같은 체크 넣고, 발견되면 빌드 실패.운영 배포 시 기본값
validate강제.
“persistence.xml이나 yml 설정은 절대 버전관리툴에 올리지 말자.
대신 템플릿만 공유하고, 실제 값은 로컬·환경변수에서 관리해야 한다.
이 작은 습관 하나가 운영 DB를 지켜준다.”