# Flyway: JDBC 프로젝트에 Flyway 적용하기

> 🇰🇷 Kor  
> 🌐 Eng: Coming Soon  
> 🇯🇵 Jap: すぐに参ります。

# Flyway란?

> Flyway는 DDL 버전 관리를 위해 사용할 수 있는 DB Migration 도구입니다. 자바 애플리케이션을 실행하기만 해도 생성되어 있는 데이터베이스 테이블들과 시드 데이터, 더미 데이터를 경험하세요!

우리가 마치 Git을 통해 소스 코드의 형상 관리를 하듯이, Flyway로 DDL 파일(`.sql`)의 형상 관리를 할 수 있습니다. 그리고 DB 마이그레이션 도구답게, 우리가 작성해 둔 SQL 파일들을 자동으로 실행해 데이터베이스 스키마의 변경을 관리하죠.

또한 Flyway를 통해서 우리는 JPA 등 ORM에 종속되는 데이터베이스 사용이 아니라, 데이터베이스에 종속되는 ORM 사용을 추구할 수 있습니다! 예를 들어, JPA를 적용한 프로젝트에서, JPA로부터 DDL 책임을 없애고 Flyway에게 그 역할을 넘길 수 있습니다.

i.e.

* DDL: Flyway로 관리
    
* DML: JPA로 관리 (*Auto-DDL 기능을 꺼 두거나(*`none`*)*`validate`*로 함.*)
    

또한 데이터베이스 스키마의 변경 이력을 알 수 있기 때문에 개발자도 DBA도 모두 편하게 일하기 위한 구성을 할 수 있습니다!

## JDBC 프로젝트에 Flyway 추가

저는 예시에서 빌드 도구를 사용합니다. 빌드도구가 없다면 IDE(이클립스, STS, 인텔리제이 등)를 통해 라이브러리를 인식시켜 주면 됩니다. IDE도 안 쓴다면 class path를 적절히 추가하세요.

### Gradle 사용 시 의존성 추가

두 가지가 모두 되어 있어야 합니다. 다음 중 JDBC는 이 글에서 직접 다루지 않습니다.

* JDBC 라이브러리 추가
    
* Flyway 라이브러리 추가
    

**MySQL 사용 시**

* group name: `org.flywaydb`
    
* artifact name: `flyway-mysql`
    
* version: `9.22.3`
    

```java
dependencis {
    implementation 'org.flywaydb:flyway-mysql:9.22.3'
}
```

**MySQL이 아닌 데이터베이스 사용 시**

* group name: `org.flywaydb`
    
* artifact name: `flyway-core`
    
* version: `9.22.3`
    

```java
dependencis {
    // 여러 DB 버전 호환을 위해 아직 9 버전대를 추천합니다.
    implementation 'org.flywaydb:flyway-core:9.22.3'
}
```

버전은 초심자의 시행착오를 줄이기 위해 9 버전대로 권장했습니다. 자신의 데이터베이스와 Flyway의 버전 호환성을 스스로 찾아서 적용해 보아도 됩니다. (예를 들어 Postgresql 14 버전은 Flyway 코어 10 버전과 호환되지 않음.)

**빌드도구 없이 IDE에서 구성 시**

실행 환경 관련 설정에 `Add Libraries ...`를 해야 합니다. 실행할 때 라이브러리를 인식할 수 있어야 하기 때문에 주로 실행 환경에 밀접한 설정에 있습니다! (IDE 없이 사용하는 경우는 class path에 실행 시 라이브러리 경로를 입력해 주어야 하거든요.)

### 커스텀 Flyway 클래스 작성

필요한 곳에서 org.flywaydb.core.Flyway 객체를 바로 사용해도 되지만, 우리는 기본적으로 깔끔한 설계 관점을 위해서 가급적 역할에 따라 클래스를 구분해 두고 사용합시다.

```java
import org.flywaydb.core.Flyway;

public class MyFlyway {
    private final Flyway flyway;
    
    public MyFlyway(String url, String username, String password) {
        flyway = Flyway.configuration()
                // DB 접속 정보
                .dataSource(url, username, password)
                // (Flyway 처음 적용 시 필요) Flyway 스키마 히스토리 테이블이 없다면 생성해 준다.
                .baselineOnMigrate(true)
                .load();
    }

    public void migrate() {
        // delegation (위임): 필드에 갖고 있는 객체가 이 클래스의 업무를 대행함.
        flyway.migrate();
    }
}
```

### Flyway 실행

애플리케이션의 초기 동작으로 추가하는 것이 좋습니다. JDBC 라이브러리가 잘 추가되어 있어야 하고, Flyway 버전과 DB의 버전이 서로 호환되어야 합니다. DB 접속 정보가 올바른지 DB 접속 툴(MySQL Workbench, HeidiSQL, DBeaver, SQL Developer 등) 등 다른 접속 수단으로 확인해 보세요.

```java
public static void Main {

    public static void main(String[] args) {
        MyFlyway flyway = new MyFlyway(
                "jdbc:로_시작하는_DB_URL",
                "DB사용자이름",
                "DB사용자암호"
        );

        flyway.migrate();

        // 이제 이곳에 다른 실행문을 작성하면 됩니다.
        // ex:
        //  MyApplication application = new MyApplication();
        //  application.run();
    }

}
```

### 참고: H2 데이터베이스 사용 시

H2 데이터베이스를 임베드로 사용하고 있다면, DB 접속 정보에 다음 옵션을 추가하는 것이 좋습니다. 복잡한 관리 방식을 사용하고 있지 않다면 필수로 넣어야 합니다.

```java
// ex) String dbUrl = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
String dbUrl = DB_URL + ";DB_CLOSE_DELAY=-1";
```

* `;DB_CLOSE_DELAY=-1`은 애플리케이션이 돌아가는 동안 H2 데이터베이스의 수명을 유지합니다.
    

---

## SQL 파일 만들어 두기

일반적으로 IDE가 관리하는 프로젝트라면, `resources` 폴더가 class path로 등록되었을 것입니다.

Flyway를 적용하려면 `resources` 폴더 하위에 `db/migration` 폴더를 만들어 두고, DDL을 작성해 둔 SQL 파일을 나열하면 됩니다.

### Flyway 파일 규칙

구분자는 `__`(언더바 두 개)입니다. `V`로 시작하는 파일이 우리가 주로 관심을 갖게 되는 파일입니다.

* `V버전__설명.sql`: DDL 작성 파일입니다. 기본적으로 수정할 수 없는 파일입니다. 대신 개발자 PC 로컬 환경에만 적용되어 있는 버전 파일은 수정할 수 있고, 파일을 수정한 경우 Flyway 히스토리 내용과 안 맞기 때문에 차라리 모든 테이블을 삭제한다고 생각하는 것이 편리합니다. (어차피 모두 Flyway가 다시 만들어 주니까요.)
    
    * ex: `V1.0.1__add_tb_user.sql`
        
    * ex: `V1_0_1__add_tb_user.sql`
        
    * ex: `V202401011030__add_tb_user.sql`
        
* `R__설명.sql`: 주로 시드데이터 작성에 사용합니다. 로컬에서는 더미 데이터 삽입에도 사용합니다.
    
    * 파일 내용이 바뀔 때마다 Flyway가 실행합니다.
