22일 차 TIL
코드에 Git이 있다면, DB에는 Liquibase가 있다.
Liquibase는 데이터베이스 버전 관리 툴이다.
DB 스키마 변경 이력을 코드처럼 관리하고,
협업 시 모든 팀원의 DB 상태를 동일하게 유지해 주는 Liquibase의 설정 방법을 살펴보자.
Liquibase를 스프링 부트에 적용하기
1. gradle에 Liquibase 의존성 추가 ( start.spring.io에서 Liquibase 검색 후 추가 )
// Liquibase
implementation 'org.liquibase:liquibase-core'
먼저 Liquibase 의존성을 gradle에 추가한다.
2. 디렉터리 구조
changelog 폴더에 DB의 변경 이력을 저장하는 용도로
DDL을 적은 sql 파일을 저장한다.
따라서 resources 하위에 다음과 같이 구성한다.
- resources에 db폴더 추가

3. db.changelog-master.yaml 추가
databaseChangeLog:
- includeAll:
path: db/changelog
relativeToChangelogFile: false
filter: com.git.prac.global.liquibase.LiquibaseIncludeFilter
모든 변경 사항을 일일이 등록하기 귀찮으므로, includeAll을 사용해 특정 폴더의 파일을 통째로 읽어오도록 설정한다.
아래의 공식 문서를 참고했다.
https://docs.liquibase.com/community/implementation-guide-5-0/set-up-your-changelog-structure
4. 필터 구현 (파일명 규칙 적용)
package com.git.prac.global.liquibase;
import java.nio.file.Paths;
import java.util.regex.Pattern;
import liquibase.changelog.IncludeAllFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
/**
* LiquibaseIncludeAllFilter
* [허용 패턴]
* - 형식: {숫자}_{설명}.sql
* - 예시: 001_create_users.sql, 02_add_column.sql, 1_init.sql
*/
@Slf4j
public class LiquibaseIncludeFilter implements IncludeAllFilter {
private static final Pattern SEQUENCE_PATTERN = Pattern.compile("^[0-9]+_[a-zA-Z0-9_]+\\.sql$");
@Override
public boolean include(String changeLogPath) {
if (!StringUtils.hasText(changeLogPath)) {
return false;
}
String fileName = Paths.get(changeLogPath).getFileName().toString();
if (fileName.startsWith(".")) {
return false;
}
boolean matches = SEQUENCE_PATTERN.matcher(fileName).matches();
if (!matches) {
log.debug("[Liquibase] Skipped file (Invalid Name): {} | Path: {}", fileName, changeLogPath);
}
return matches;
}
}
위 필터는 스키마를 생성할 때 사용할 파일명을 체크하는데,
{숫자}_{설명}.sql 형식으로 제한할 수 있다.
파일명 예시) 01_create_user.sql
5. SQL 파일 작성
파일 상단에 -- liquibase formatted sql과 -- changeset 작성자:ID를 적어줘야
Liquibase가 변경 이력으로 인식한다.
-- liquibase formatted sql
-- changeset Jaehyun-Kim:01-create-p-store-table
CREATE TABLE p_store
(
store_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '가게 ID',
user_id BIGINT NOT NULL COMMENT '사장님 ID',
address_id BIGINT NOT NULL COMMENT '가게 주소 ID',
name VARCHAR(100) NOT NULL COMMENT '상호명',
rating_avg DECIMAL(2,1) NOT NULL DEFAULT 0.0 COMMENT '가게 평점',
review_count INT NOT NULL DEFAULT 0 COMMENT '리뷰 수',
detail_address VARCHAR(255) NOT NULL COMMENT '상세 주소',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '레코드 생성 시간',
created_by VARCHAR(100) NOT NULL COMMENT '레코드 생성자',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '레코드 수정 시간',
updated_by VARCHAR(100) NOT NULL COMMENT '레코드 수정자',
deleted_at TIMESTAMP NULL COMMENT '레코드 삭제 시간',
deleted_by VARCHAR(100) NULL COMMENT '레코드 삭제자',
-- Constraints
CONSTRAINT pk_store PRIMARY KEY (store_id),
CONSTRAINT ck_store_rating_range CHECK (rating_avg BETWEEN 0.0 AND 5.0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- rollback DROP TABLE p_store;
-- Indexes
CREATE INDEX idx_store_user_id ON p_store (user_id);
CREATE INDEX idx_store_address_id ON p_store (address_id);
-- rollback DROP INDEX idx_store_user_id;
-- rollback DROP INDEX idx_store_address_id;
스키마 구조를 변경하고 싶다면 새로운 sql 파일을 저장하면 된다.
컬럼 추가 예시)
-- liquibase formatted sql
-- changeset your.name:4
ALTER TABLE person ADD nickname VARCHAR(30);
또는 yaml 파일을 변경할 수도 있다.
databaseChangeLog:
- includeAll:
path: db/changelog
# ... (기존 설정)
# includeAll 아래에 추가 가능
- changeSet:
id: 4
author: your.name
changes:
- addColumn:
tableName: person
columns:
- column:
name: nickname
type: varchar(30)
6. Application 설정 (YML)
Liquibase가 master 파일을 어디서 찾을지 알려줘야 한다.
spring:
liquibase:
enabled: true # 기본적으로 활성화
change-log: classpath:db/db.changelog-master.yaml
7. 결과 확인
애플리케이션을 실행하면 콘솔에 Liquibase 로그가 찍히며 DB에 두 개의 테이블이 추가로 생성된다.
- DATABASECHANGELOG: 어떤 SQL이 실행되었는지 기록 (여기에 기록된 파일은 다시 실행 안 됨)
- DATABASECHANGELOGLOCK: 동시에 여러 명이 배포할 때 DB 충돌 방지용 잠금장치
'내배캠' 카테고리의 다른 글
| [내일배움캠프] 24일 차 TIL 클린 아키텍처와 DDD (0) | 2026.03.05 |
|---|---|
| 토스 사용 시, 결제 시나리오 (0) | 2026.03.04 |
| [내일배움캠프] 21일 차 TIL QueryDSL 적용 방법 (0) | 2026.03.02 |
| [내일배움캠프] 20일 차 TIL Github Rules, Code Convention (0) | 2026.03.01 |
| [내일배움캠프] 19일 차 TIL 도메인 중심 아키텍처 (0) | 2026.03.01 |


