KotlinとSpring Bootで構築したアプリケーションからMySQLにアクセスしHello Worldする

この記事ではKotlin, Spring Boot, MySQLを利用してHello Worldを保存、出力します。

## MySQLイメージを用意し、docker-composeで立ち上げる

```yaml:docker-compose.yml
version: '3'
services:
    mysql:
        image: mysql:5.7
        container_name: mysql_playground
        environment:
            MYSQL_ROOT_PASSWORD: mysql
            MYSQL_DATABASE: playground
            MYSQL_USER: docker
            MYSQL_PASSWORD: docker
        volumes:
            ./mysql/init:/docker-entrypoint-initdb.d
        ports:
            3306:3306
```

`/docker-entrypoint-initidb.d`にSQLファイルを格納しておくと、container起動時に自動で実行される。

ここではデータベースとテーブルを作成するDDLのSQLを格納しておく。

```mysql
CREATE TABLE hello_worlds
(
    `id`   int(11)      NOT NULL AUTO_INCREMENT,
        `hello_world` varchar(100) NOT NULL DEFAULT 'Hello, World!',
        PRIMARY KEY (id)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
```

docker-composeの設定が完了したので起動確認を行います。

```bash
$ docker-compose up
Creating network "simple-mysql_default" with the default driver
Creating mysql_helloworld ... done
Attaching to mysql_helloworld 
mysql_helloworld | Initializing database
(...)
mysql_helloworld | 2019-12-28T02:39:53.408712Z 0 [Note] mysqld: ready for connections.
mysql_helloworld | Version: '5.7.27'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
```

起動できましたね、次に立ち上がったMySQLにローカルのmysqlコマンドを利用して接続します。

```bash
$ mysql -h 0.0.0.0 -u helloworld_user -p
mysql>  SHOW VARIABLES LIKE "%version%";
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 5.7.27                       |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| tls_version             | TLSv1,TLSv1.1                |
| version                 | 5.7.27                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
8 rows in set (0.01 sec)
```

## Spring Bootアプリケーションを用意する

前回の記事([KotlinとSpring BootのアプリケーションでHello Worldを返すエンドポイントを実装する](https://qiita.com/wildmouse/items/89314b1e3168b899cc67))で作成したSpring Boot Applicationをベースにします。

まずDependenciesにSpring JPA, MySQL Driverを追加します(ktsファイルなので気をつけて下さい)。

```gradle:build.gradle.kts
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    runtimeOnly ("mysql:mysql-connector-java")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
    }
}
```

Dependenciesの設定ができたら、次にMySQLに接続するための接続情報を記述する必要があります。

```properties:application.properties
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://0.0.0.0:3306/helloworld
spring.datasource.username=helloworld_user
spring.datasource.password=helloworld
```

これでアプリケーションからの接続設定は完了です。実際にMySQLを利用するコードを記述していきます。

```kotlin:Controller
    @RestController
    class HelloWorldController(private val service: HelloWorldService) {
        @GetMapping("/hello-worlds/{id}")
        fun getHelloWorld(@PathVariable("id") id: Int) = service.getHelloWorld(id)

        @GetMapping("/hello-worlds")
        fun getHelloWorldList() = service.getHelloWorldList()
        @PostMapping("/hello-worlds")
        fun saveHelloWorld(@RequestParam("message") message: String) =
            service.insertHelloWorld(message)
    }
```

```kotlin:Service
    @Service
    class HelloWorldService(
        private val repository: HelloWorldRepository
    ) {
        fun getHelloWorld(id: Int) = repository.findById(id)
        fun getHelloWorldList() = repository.findAll()
        fun insertHelloWorld(message: String) = HelloWorld(message).let { repository.save(it) }
    }
```

```kotlin:Repository
    interface HelloWorldRepository : CrudRepository<HelloWorld, Int>
```

```kotlin:Entity
    @Entity
    data class HelloWorld(
        var message: String = "Hello, World!",
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        var id: Int = 0
    )
```

以上でアプリケーションコードの記述が完了です。

アプリケーションを起動し、前回と同じくcurlでPOST, GETリクエストを行いHello Worldを保存、取得します。

```bash
$ gradle bootRun
(...)
2019-12-28 12:15:00.727  INFO 52141 --- [           main] c.e.helloworld.HelloworldApplicationKt   : Started HelloworldApplicationKt in 4.021 seconds (JVM running for 4.415)

$ curl -X POST --data 'message=Hello, World!' localhost:8080/hello-worlds
{"message":"Hello, World!","id":1}

$ curl -X POST --data 'message=Hello, World!' localhost:8080/hello-worlds
{"message":"Hello, World!","id":2}

$ curl localhost:8080/hello-worlds/1
{"message":"Hello, World","id":1}

$ curl localhost:8080/hello-worlds
[{"message":"Hello, World!","id":1},{"message":"Hello, World!","id":2}]
```
Hello, World!