# Flyway 로 DataBase 형상 관리해보자

git 으로 source code 를 관리할수 있는건 누구나 다 아는 사실. 하지만 db는 할수 없다. 이 처럼 db의 형상관리를 할수 는 녀석이 바로 Flyway 다 .

<figure><img src="https://3202568828-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgVNjdXkr3ciD8p5jXPCI%2Fuploads%2FDiGLl5hCVc3l50880xNA%2Fimage.png?alt=media&#x26;token=5b4ae815-1942-4c9a-ac42-8efbf8b74ae1" alt=""><figcaption><p><a href="https://flywaydb.org/">https://flywaydb.org/</a></p></figcaption></figure>

&#x20;

공식사이트에 기재되어 있는 flyway 작동방식을 설명해주는 많이 보았을 이미지 이다.

flyway를 잘 사용하면 이렇게 Axel 과 Christian 라는 개발자 각자 필요한 DDL 을 만들고 배포할수 잇다. 공식사이트 소개를 예로 들자면 gradle, maven, CLI, java api 를 통하여 flyway 를 실행할수 있다고 하는데 이글에서 springboot 으로 실행하는 방법을 알아보자.

### pom.xml dependency 추가&#x20;

```xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-core</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
```

#### src/main/resources 폴더에 db 폴더 ,그리고 그안에  migration  폴더를 만든다.

migration 폴더에 V1\_\_Base\_version.sql 파일을 생성

```sql
DROP TABLE IF EXISTS user ;
CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'pk',
  `name` varchar(20) NOT NULL COMMENT '이름',
  `age` int(5) DEFAULT NULL COMMENT '나이',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

{% hint style="info" %}
주의 : .sql 경로를 혹시 자기가 원하는 폴더에 위치하고 싶으면 spring.flyway.locations 설정을 하면 된다.
{% endhint %}

### User 객체 생성&#x20;

```java
@Data
@NoArgsConstructor
public class User {

    private Long id;
    private String name;
    private Integer age;

}
```

### Interface 작성

```java
public interface UserService {

    int create(String name, Integer age);
    
    List<User> getByName(String name);

    int deleteByName(String name);

    int getAllUsers();

    int deleteAllUsers();

}

@Service
public class UserServiceImpl implements UserService {

    private JdbcTemplate jdbcTemplate;

    UserServiceImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public int create(String name, Integer age) {
        return jdbcTemplate.update("insert into USER(NAME, AGE) values(?, ?)", name, age);
    }

    @Override
    public List<User> getByName(String name) {
        List<User> users = jdbcTemplate.query("select * from USER where NAME = ?", (resultSet, i) -> {
            User user = new User();
            user.setId(resultSet.getLong("ID"));
            user.setName(resultSet.getString("NAME"));
            user.setAge(resultSet.getInt("AGE"));
            return user;
        }, name);
        return users;
    }

    @Override
    public int deleteByName(String name) {
        return jdbcTemplate.update("delete from USER where NAME = ?", name);
    }

    @Override
    public int getAllUsers() {
        return jdbcTemplate.queryForObject("select count(1) from USER", Integer.class);
    }

    @Override
    public int deleteAllUsers() {
        return jdbcTemplate.update("delete from USER");
    }

}
```

### 테스트 코드 작성

```java
@Slf4j
@SpringBootTest
public class FlywayDemoApplicationTests {

    @Autowired
    private UserService userSerivce;

    @Test
    public void test() throws Exception {
        userSerivce.deleteAllUsers();

        userSerivce.create("Tom", 10);
        userSerivce.create("Mike", 11);
        userSerivce.create("Didispace", 30);
        userSerivce.create("Oscar", 21);
        userSerivce.create("Linda", 17);

        // Oscar 라는 이름을 가진 사용자 조회 , 나이 가 정확한지 확인.
        List<User> userList = userSerivce.getByName("Oscar");
        Assertions.assertEquals(21, userList.get(0).getAge().intValue());

        // 5명 있음.
        Assertions.assertEquals(5, userSerivce.getAllUsers());

        // 2명 삭제.
        userSerivce.deleteByName("Tom");
        userSerivce.deleteByName("Mike");

        // 아직 5명 있을걸?
        Assertions.assertEquals(3, userSerivce.getAllUsers());
    }

}
```

#### 테스트 코드 실행 결과

<figure><img src="https://3202568828-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgVNjdXkr3ciD8p5jXPCI%2Fuploads%2FYZGbkxTWqj6Z8pFaJ7zk%2Fimage.png?alt=media&#x26;token=0ddf9906-4199-49f9-8832-c5b9f6d141c2" alt=""><figcaption></figcaption></figure>

디비테이블 확인 2개 추가 된걸 확인 할수 있다.

<figure><img src="https://3202568828-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgVNjdXkr3ciD8p5jXPCI%2Fuploads%2Fg8SfBqumK6R2iUxSpRDp%2Fimage.png?alt=media&#x26;token=a6622755-1212-4efc-b5ee-da0e1c3f6c68" alt=""><figcaption></figcaption></figure>

* user 현재 테이블
* flyway\_schema\_history : flyway가 관리하고 있는 테이블. 해당 테이블에 수행된 .sql 스크립트 내역들을 기재하고 있다.

#### 위 내용을 이서 진행해보자.

만일 특정 개발자가 address 라는 컬럼을 테이블에 추가했다면 어떻게 될까?&#x20;

```sql
ALTER TABLE `user` ADD COLUMN `address` VARCHAR(20) DEFAULT NULL;
```

{% hint style="info" %}
스크립트 파일 명명 규칙은 버전번호\_쿼리에 대한 *설명 .sql 이다.*
{% endhint %}

#### 다시 테스트 코드를 돌리면 아래와 같은 수행완료 로그를 볼수 있다.

```
2022-12-26 16:58:12.025  INFO 37330 --- [           main] o.f.c.i.database.base.DatabaseType       : Database: jdbc:mysql://localhost:3306/test (MySQL 8.0)
2022-12-26 16:58:12.063  INFO 37330 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.020s)
2022-12-26 16:58:12.075  INFO 37330 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `test`: 1
2022-12-26 16:58:12.082  INFO 37330 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `test` to version "1.1 - alter table user"
2022-12-26 16:58:12.113  INFO 37330 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `test` (execution time 00:00.045s)

```

#### 테이블을 확인해보자

<figure><img src="https://3202568828-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgVNjdXkr3ciD8p5jXPCI%2Fuploads%2F7W2xTNYhBmHAcI9woH2T%2Fimage.png?alt=media&#x26;token=1634aa99-cd50-4235-8dfb-d61e8299626f" alt=""><figcaption></figcaption></figure>

마찬가리로 history 테이블에도 아래와 같이 내역이 추가되었다.

<figure><img src="https://3202568828-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgVNjdXkr3ciD8p5jXPCI%2Fuploads%2F5Yz9tbExWg8RZhBNExVV%2Fimage.png?alt=media&#x26;token=1602eda7-46a4-41e3-9aaf-adf2ccafd340" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blakes-organization.gitbook.io/rainsister/springboot-2.x/database-connection/flyway-database.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
