create는 애플리케이션 시작 시 스키마를 드롭하고 재생성한다.
CI/CD, 프로파일/환경 변수 실수, 다중 인스턴스, Flyway/Liquibase와 혼용 시 무경고 데이터 증발이 발생한다.
운영은 마이그레이션 도구(Flyway/Liquibase) + validate/none 조합으로.
개발은 update도 남용 금지. 테스트 컨테이너/임베디드 DB로 격리하자.
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 권한이 열려있으면 방어막이 전혀 없음.
공통점: 경고 없이 “정상 동작”처럼 보이며 데이터가 사라진다는 것.
spring.jpa.hibernate.ddl-auto=validate 또는 none
스키마 변경은 Flyway/Liquibase에만 맡긴다.
운영 DB 계정 권한 최소화(DDL 불가).
드라이런(마이그레이션 시뮬레이션) + 백업 자동화.
validate 권장.
스키마는 운영과 동일하게 마이그레이션 스크립트로만 갱신.
롤백 시나리오(다운 마이그레이션) 준비.
빠른 실험은 가능하지만 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: ****
@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 금지!");
}
}
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")
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;
현행 스키마 스냅샷: pg_dump -s 등으로 구조만 덤프 → V1__baseline.sql.
spring.jpa.hibernate.ddl-auto=validate 로 다운그레이드.
이후 변경은 V2__...sql, V3__...sql로 관리.
롤링 배포 시 forwards-only 전략(다운 마이그레이션은 별도 브랜치로 검증).
배포 전 Flyway info, migrate -dryRunOutput로 시뮬레이션.
테스트 컨테이너
@Container
static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres:16");
별도 프로파일: local-reset 같은 임시 프로파일에서만 create 허용, 기본은 항상 validate.
샌드박스 DB: 운영 VPC와 물리적으로 분리.
운영 프로파일에 ddl-auto=validate/none 인가?
운영 DB 계정 DDL 권한 제거됐는가?
Flyway/Liquibase로만 스키마 변경하는가?
배포 파이프라인에서 프로파일/환경 변수 검증하는가?
create/create-drop은 샌드박스에서만 가능한가?
배포 전 백업·드라이런 자동화가 있는가?
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를 지켜준다.”