Skip to content

Commit d66e77a

Browse files
authored
Merge pull request #344 from EAT-SSU/feature/#343-db-migration
feat: DB 마이그레이션 스크립트 추가
2 parents 244712f + 0356bd9 commit d66e77a

12 files changed

Lines changed: 761 additions & 0 deletions

MIGRATION_GUIDE.md

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# DB 마이그레이션 실행 가이드
2+
3+
## 📁 마이그레이션 파일 목록
4+
5+
```
6+
src/main/resources/db/migration/
7+
├── V2__align_pk_and_fk_types.sql (PK/FK bigint 통일)
8+
├── V3__convert_varchar_to_enum.sql (varchar → enum 변환)
9+
└── V4__add_constraints_and_defaults.sql (제약조건 및 기본값)
10+
```
11+
12+
## 🚀 실행 순서
13+
14+
### 1️⃣ 사전 준비 (필수)
15+
16+
#### ✅ 스냅샷 확인
17+
- [ ] Dev DB 스냅샷 생성 완료
18+
- [ ] Prod DB 스냅샷 생성 완료 (실제 배포 전)
19+
20+
#### ✅ 데이터 검증 (필수)
21+
```bash
22+
# varchar 데이터가 Enum과 일치하는지 검증
23+
./run_validation.sh
24+
```
25+
26+
**중요:** 검증 결과가 비어있어야 정상 (불일치 데이터 없음)
27+
28+
#### ✅ FK 제약조건명 확인 (선택)
29+
```bash
30+
# department, partnership의 FK 이름 확인
31+
mysql -h <host> -u <user> -p <database> < check_fk_constraints.sql
32+
```
33+
34+
---
35+
36+
### 2️⃣ Dev 환경 마이그레이션
37+
38+
#### 방법 1: Flyway 자동 실행 (권장)
39+
```bash
40+
# application-dev.yml의 spring.flyway 설정 확인
41+
# spring.jpa.hibernate.ddl-auto: none 확인
42+
43+
# 애플리케이션 실행 시 자동으로 마이그레이션 실행
44+
./gradlew bootRun --args='--spring.profiles.active=dev'
45+
```
46+
47+
#### 방법 2: 수동 실행
48+
```bash
49+
# V2 실행
50+
mysql -h <host> -u <user> -p <database> < src/main/resources/db/migration/V2__align_pk_and_fk_types.sql
51+
52+
# 검증: PK/FK 타입 확인
53+
mysql -h <host> -u <user> -p -e "
54+
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
55+
FROM information_schema.COLUMNS
56+
WHERE TABLE_SCHEMA = '<database>'
57+
AND COLUMN_NAME IN ('college_id', 'department_id')
58+
ORDER BY TABLE_NAME;
59+
"
60+
61+
# V3 실행
62+
mysql -h <host> -u <user> -p <database> < src/main/resources/db/migration/V3__convert_varchar_to_enum.sql
63+
64+
# 검증: Enum 타입 확인
65+
mysql -h <host> -u <user> -p -e "
66+
SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE
67+
FROM information_schema.COLUMNS
68+
WHERE TABLE_SCHEMA = '<database>'
69+
AND DATA_TYPE = 'enum'
70+
ORDER BY TABLE_NAME;
71+
"
72+
73+
# V4 실행
74+
mysql -h <host> -u <user> -p <database> < src/main/resources/db/migration/V4__add_constraints_and_defaults.sql
75+
76+
# 검증: 제약조건 확인
77+
mysql -h <host> -u <user> -p -e "
78+
SHOW CREATE TABLE college;
79+
SHOW CREATE TABLE menu;
80+
SHOW CREATE TABLE review;
81+
"
82+
```
83+
84+
---
85+
86+
### 3️⃣ 마이그레이션 검증
87+
88+
#### 애플리케이션 테스트
89+
```bash
90+
# 애플리케이션 재시작
91+
./gradlew bootRun --args='--spring.profiles.active=dev'
92+
93+
# 로그 확인
94+
# - Enum 매핑 오류 없는지
95+
# - DB 연결 정상인지
96+
# - API 호출 정상인지
97+
```
98+
99+
#### DB 데이터 확인
100+
```sql
101+
-- Enum 값 조회 테스트
102+
SELECT restaurant, time_part FROM meal LIMIT 10;
103+
SELECT provider, role, status FROM user LIMIT 10;
104+
105+
-- PK/FK 타입 확인
106+
SELECT
107+
TABLE_NAME,
108+
COLUMN_NAME,
109+
DATA_TYPE,
110+
COLUMN_TYPE
111+
FROM information_schema.COLUMNS
112+
WHERE TABLE_SCHEMA = '<database>'
113+
AND COLUMN_NAME IN ('college_id', 'department_id')
114+
ORDER BY TABLE_NAME, COLUMN_NAME;
115+
116+
-- 제약조건 확인
117+
SELECT
118+
TABLE_NAME,
119+
CONSTRAINT_NAME,
120+
CONSTRAINT_TYPE
121+
FROM information_schema.TABLE_CONSTRAINTS
122+
WHERE TABLE_SCHEMA = '<database>'
123+
AND TABLE_NAME IN ('college', 'menu', 'review');
124+
```
125+
126+
---
127+
128+
### 4️⃣ Prod 환경 마이그레이션
129+
130+
#### 실행 전 체크리스트
131+
- [ ] Dev 환경 마이그레이션 완료 및 검증
132+
- [ ] Dev 환경 애플리케이션 정상 동작 확인
133+
- [ ] Prod DB 스냅샷 생성 완료
134+
- [ ] 데이터 검증 (validate_enum_data.sql) 완료
135+
- [ ] 사용량이 적은 시간대 선택 (새벽 2-4시 권장)
136+
- [ ] 롤백 계획 수립
137+
138+
#### 실행
139+
```bash
140+
# Prod 환경에서 동일하게 실행
141+
./gradlew bootRun --args='--spring.profiles.active=prod'
142+
143+
# 또는 수동 실행
144+
mysql -h <prod-host> -u <user> -p <database> < V2__align_pk_and_fk_types.sql
145+
mysql -h <prod-host> -u <user> -p <database> < V3__convert_varchar_to_enum.sql
146+
mysql -h <prod-host> -u <user> -p <database> < V4__add_constraints_and_defaults.sql
147+
```
148+
149+
---
150+
151+
## ⚠️ 주의사항
152+
153+
### 1. metadata lock 방지
154+
- 사용량이 적은 시간대에 실행
155+
- 실행 중 다른 세션에서 DDL 작업 금지
156+
157+
### 2. 데이터 검증 필수
158+
```bash
159+
# V3 실행 전 반드시 검증
160+
./run_validation.sh
161+
```
162+
163+
### 3. FK 제약조건 처리
164+
- V2에서 `SET FOREIGN_KEY_CHECKS = 0/1` 사용
165+
- FK 제약조건은 자동으로 유지됨
166+
167+
### 4. 롤백 방법
168+
```bash
169+
# AWS RDS 스냅샷으로 복원
170+
aws rds restore-db-instance-from-db-snapshot \
171+
--db-instance-identifier your-db-restored \
172+
--db-snapshot-identifier eatssu-dev-pre-migration-20260207
173+
```
174+
175+
---
176+
177+
## 🐛 문제 발생 시
178+
179+
### 1. Enum 변환 실패
180+
```
181+
ERROR 1265: Data truncated for column 'restaurant' at row 1
182+
```
183+
**원인:** DB에 Enum에 없는 값이 존재
184+
**해결:** `validate_enum_data.sql` 실행하여 불일치 데이터 찾기
185+
186+
### 2. PK 타입 변경 실패
187+
```
188+
ERROR 1833: Cannot change column: used in a foreign key constraint
189+
```
190+
**원인:** FK 제약조건이 걸려있음
191+
**해결:** V2 파일에 `SET FOREIGN_KEY_CHECKS = 0` 이미 포함됨
192+
193+
### 3. unique 제약조건 실패
194+
```
195+
ERROR 1062: Duplicate entry for key 'UK_college_name'
196+
```
197+
**원인:** college.name에 중복 데이터 존재
198+
**해결:** 중복 데이터 정리 후 다시 실행
199+
200+
---
201+
202+
## ✅ 완료 확인
203+
204+
- [ ] V2, V3, V4 모두 정상 실행
205+
- [ ] flyway_schema_history 테이블에 기록 확인
206+
- [ ] 애플리케이션 정상 동작 확인
207+
- [ ] API 테스트 통과
208+
- [ ] 로그에 오류 없음

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ repositories {
3131

3232
dependencies {
3333
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
34+
implementation 'org.flywaydb:flyway-core'
35+
implementation 'org.flywaydb:flyway-mysql'
3436
implementation 'org.springframework.boot:spring-boot-starter-web'
3537
implementation 'org.jetbrains:annotations:20.1.0'
3638
implementation 'org.springframework.boot:spring-boot-starter-security'

check_fk_constraints.sql

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-- =========================
2+
-- FK 제약조건명 확인
3+
-- =========================
4+
-- 실행 방법: mysql -h <host> -u <user> -p <database> < check_fk_constraints.sql
5+
6+
-- department, partnership 테이블의 FK 제약조건 확인
7+
SELECT
8+
CONSTRAINT_NAME AS 'FK 이름',
9+
TABLE_NAME AS '테이블',
10+
COLUMN_NAME AS '컬럼',
11+
REFERENCED_TABLE_NAME AS '참조 테이블',
12+
REFERENCED_COLUMN_NAME AS '참조 컬럼'
13+
FROM information_schema.KEY_COLUMN_USAGE
14+
WHERE TABLE_SCHEMA = DATABASE()
15+
AND REFERENCED_TABLE_NAME IS NOT NULL
16+
AND TABLE_NAME IN ('department', 'partnership')
17+
ORDER BY TABLE_NAME, CONSTRAINT_NAME;
18+
19+
-- =========================
20+
-- 전체 FK 제약조건 확인 (참고용)
21+
-- =========================
22+
SELECT
23+
TABLE_NAME AS '테이블',
24+
CONSTRAINT_NAME AS 'FK 이름',
25+
COLUMN_NAME AS '컬럼',
26+
REFERENCED_TABLE_NAME AS '참조 테이블',
27+
REFERENCED_COLUMN_NAME AS '참조 컬럼'
28+
FROM information_schema.KEY_COLUMN_USAGE
29+
WHERE TABLE_SCHEMA = DATABASE()
30+
AND REFERENCED_TABLE_NAME IS NOT NULL
31+
ORDER BY TABLE_NAME, CONSTRAINT_NAME;

run_validation.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
3+
# =========================
4+
# Enum 데이터 검증 스크립트
5+
# =========================
6+
7+
echo "=========================================="
8+
echo "Enum 데이터 검증 시작"
9+
echo "=========================================="
10+
echo ""
11+
12+
# 사용자에게 환경 선택
13+
read -p "검증할 환경을 선택하세요 (dev/prod): " ENV
14+
15+
if [ "$ENV" != "dev" ] && [ "$ENV" != "prod" ]; then
16+
echo "오류: 'dev' 또는 'prod'만 입력 가능합니다."
17+
exit 1
18+
fi
19+
20+
# DB 접속 정보 입력
21+
read -p "DB 호스트를 입력하세요: " DB_HOST
22+
read -p "DB 사용자명을 입력하세요: " DB_USER
23+
read -sp "DB 비밀번호를 입력하세요: " DB_PASS
24+
echo ""
25+
read -p "DB 이름을 입력하세요: " DB_NAME
26+
27+
echo ""
28+
echo "[$ENV 환경] 데이터 검증을 시작합니다..."
29+
echo ""
30+
31+
# 검증 쿼리 실행
32+
RESULT_FILE="validation_result_${ENV}_$(date +%Y%m%d_%H%M%S).txt"
33+
mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" < validate_enum_data.sql > "$RESULT_FILE" 2>&1
34+
35+
if [ $? -eq 0 ]; then
36+
echo "✅ 검증 완료! 결과 파일을 확인하세요: $RESULT_FILE"
37+
echo ""
38+
echo "⚠️ 중요: 결과 파일에서 아래 내용을 확인하세요"
39+
echo " - 불일치 데이터가 있는 경우: 데이터 정리 후 다시 검증"
40+
echo " - 결과가 비어있는 경우: varchar → enum 변환 진행 가능"
41+
echo ""
42+
else
43+
echo "❌ 검증 실패. 접속 정보를 확인하세요."
44+
exit 1
45+
fi

src/main/resources/application-dev.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ server:
55

66

77
spring:
8+
## Flyway
9+
flyway:
10+
enabled: true
11+
baseline-on-migrate: true
12+
baseline-version: 1
13+
locations: classpath:db/migration
14+
815
## Database
916
datasource:
1017
driver-class-name: com.mysql.cj.jdbc.Driver

src/main/resources/application-prod.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ server:
55

66

77
spring:
8+
## Flyway
9+
flyway:
10+
enabled: true
11+
baseline-on-migrate: true
12+
baseline-version: 1
13+
locations: classpath:db/migration
14+
815
## Database
916
datasource:
1017
driver-class-name: com.mysql.cj.jdbc.Driver

0 commit comments

Comments
 (0)