Skip to content

Commit

Permalink
flyway 글 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
drunkenhw committed Aug 28, 2023
1 parent 482326c commit 3407bb2
Showing 1 changed file with 123 additions and 0 deletions.
123 changes: 123 additions & 0 deletions _posts/2023-08-29-flyway.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: 'Flyway'
excerpt: "Flyway를 늦게라도 적용한 이유"

categories:
- java
- flyway
tags:
- flyway
last_modified_at: 2023-08-29T19:14:00-05:00
---

안녕하세요

## 이 글을 쓰는 이유

저희 팀은 flyway를 적용했습니다. 가장 큰 이유는 데이터베이스의 데이터를 drop 할 수 없기 때문입니다.

데이터베이스를 drop하는 것과 flyway가 무슨 상관이 있길래 적용할까요.

### 예시 상황

제가 아래와 같이 Member라는 entity를 만들었습니다.

```java
class Member {

private Long id;
private String name;
}
```
지금의 entity는 두개의 필드 밖에 없습니다. 어느 날부터 Member에 email이라는 정보가 있어야한다는 요구사항이 생깁니다.
그래서 저희는 아래와 같이 email을 추가합니다.
```java
class Member {

private Long id;
private String name;
private String email;
}
```
그리고 다시 jpa의 ddl-auto 속성 중 create를 사용해서 새로운 테이블을 만들었습니다. 기존의 테이블을 다 날리면서요.

하지만 저희의 데이터베이스의 데이터들을 그냥 drop해도 되는 것일까요?
개발 서버라도 힘들게 쌓은 데이터들을 테이블이 조금 변경되었다고 날려버리는 것은 바보같은 일이라고 생각했습니다.
그러면 ddl-auto의 다른 조건인 update를 사용하면 될 것 같습니다. 그랬더니 jpa가 아래와 같이 쿼리를 이쁘게 만들어 줬습니다.
```sql
ALTER TABLE member
ADD COLUMN email varchar(255);
```
update를 사용하니 아주 편하게 칼럼이 추가되는 것을 볼 수 있습니다.

하지만 여기서 또 아래와 같은 요구사항이 추가되었습니다.

email의 제약조건으로 null이 되면 안되고, 길이는 20자가 되어야합니다.
그러면 어노테이션을 사용하여 변경해보겠습니다.
```java
class Member {

private Long id;
private String name;
@Column(nullable= false, length = 20)
private String email;
}
```
이렇게 하고 어플리케이션을 재시작 했습니다.
하지만 아무런 ddl이 발생하지 않습니다. 왜냐면 Jpa의 ddl-auto: update의 속성은 제약조건이 변경된 것은 반영해주지 않기 때문입니다.

그리고 만약 이 전의 회원들의 email이 null인 row도 있다면 어떻게 될까요? 제약조건을 반영할 수 없을 것입니다.

이런 식으로 운영 도중 table의 칼럼들이 추가되거나, 삭제되거나, 혹은 제약조건이 변경될 때 update 속성만으로는 반영할 수 없습니다.

## flyway

그래서 flyway를 사용했습니다.
물론 flyway 없이도 이런 문제를 해결할 수 있습니다. 방법은 간단합니다. 데이터베이스가 있는 서버에 직접 접속하여 ddl을 직접 하나 하나 다 작성하면 됩니다.

하지만 이런 방식에는 단점이 있습니다. 하나 하나 직접 입력하다보니 휴먼 에러가 발생할 수도 있기 때문입니다. 그리고 매번 데이터베이스 서버에 접속해야한다는 단점이 있습니다.
이렇게 매번 데이터베이스에 접속을 해야한다면 cd를 하는 이유가 있을까요?

하지만 flyway를 사용하면 편하게 변경된 schema를 관리할 수 있고 언제 바뀌었는지 어떻게 바뀌었는지 확인도 할 수 있습니다.

글로는 잘 와닿지 않을 수도 있으니 사용법을 확인하면서 어떤 장점이 있는지 확인해보도록 하겠습니다.

먼저 flyway 의존성을 추가하고 `resources/db/migration` 패키지를 만듭니다.
거기에 file을 만듭니다. 파일 이름이 중요한데요 `V1__init.sql` 이러한 방식으로 `V{version 숫자}__{어떠한 파일인지에 대한 이름}.sql` 언더스코어 2개는 필수로 작성해야합니다.

```sql
create table member(
id bigint auto_increment primary key,
name varchar(255) null,
);
```
이렇게 `V1__init.sql`에 대한 파일을 작성했습니다. 이제는 email을 추가한다는 요구사항을 반영해보겠습니다.

```sql
ALTER TABLE member
ADD COLUMN email varchar(255);
```
이렇게 새로운 파일을 만들어서 해당 스크립트를 작성했습니다. 파일명이 중요한데요, 이전 파일의 숫자보다 +1 이 되는 숫자를 V 뒤에 붙입니다.

따라서 이번 파일은 `V2__add_column_email.sql` 이라고 만들었습니다.

그럼 이제 또 시간이 지나 회원이 많아졌습니다. 하지만 email이 없는 사용자도 많습니다. 이 상황에서 email을 not null로 변경해야한다는 요구사항이 생겼습니다.

그러면 아래와 같이 반영할 수 있습니다.
```sql
ALTER TABLE member
MODIFY email VARCHAR(20) NOT NULL default 'default'
```
이렇게 `V3__add_constraints.sql` 파일을 만들었습니다. 그러면 null이 있던 row들은 email이 default가 되고 not null 제약조건이 활성화 된 것을 볼 수 있습니다.

그러면 주어진 요구사항은 모두 만족할 수 있습니다. 거기에다 v1, v2, v3 가 나뉘어져있어서 어느 커밋부터 해당 sql이 추가되었는지도 확인할 수 있습니다.

그리고 ddl-auto update를 사용하면 반영되지 않았던 제약조건의 추가도 확인할 수 있습니다. 그러면 ddl-auto의 속성을 validate로 변경하여, db schema와 entity의 필드가 다르면
어플리케이션이 실행되지 않도록 해서 좀 더 안전한 개발을 할 수 있습니다.

## 결론

flyway는 roll back을 하는 것이 유료라서, production 서버에서 혹은 롤백을 해야하는 일이 있는 서버에서는 사용하는 것이 좋지 않지만,
이와 같이 데이터를 drop 할 수 없는 상황이라면, 사용하지 않을 이유가 없어보이는 좋은 도구입니다.

짧은 글 읽어주셔서 감사합니다.

0 comments on commit 3407bb2

Please sign in to comment.