Help us understand the problem. What is going on with this article?

Ktor + Exposedを使ってlocalhostでMySQLに接続(with MAMP)

はじめに

こんにちは!tasukuです!
今回はMySQLからデータをSELECTしてこようと思います!
(Insertやら他のはExposedについての記事をまた別の機会に書こうと思っています)

・どうやらKtorでDBと接続するときはExposedというライブラリが一般的らしいので今回はそれを使います
・MAMPを使うとphpmyadmin使えるしDBの設定とかも楽なのでDBサーバーにはMAMPを使います

Exposedのgithubはこちらになります。
https://github.com/JetBrains/Exposed/wiki/Getting-Started

環境

・macOS Mojave (10.14.5)
・IntelliJ IDEA (2019.2.2)
・Exoposed (0.16.1)
・MAMP (5.5)
・MAMPの中のMySQL(5.7.26)

実装の前に

まずは実装の前にMAMPのMySQLにデータを準備しましょう(mampやphpmyadminの説明になってしまうので軽めにいきます)
必要のない方はここは飛ばしちゃってください

DB作成します

MAMPを起動してphpMyAdminを開きます。そうするとこんな画面が開きます。
(すでに自分で作ったDBが何個かありますが気にしないでください。。)
スクリーンショット 2019-09-10 13.23.27.png

画面左にNewってのがあるのでそこを押すとDB作成画面へ移ります。今回はExposedSampleというDB名にすることにします。名前を入力したらあとはいじらずにcreateを押します。
スクリーンショット 2019-09-10 13.25.31.png

そうするとテーブル名の入力を求められるので今回はTable1にしておきます。そして次に進みます(画像は割愛)

そうすると次に各カラムの名前や型などを決める画面に移ります。
わかる方は適当に作っちゃってください
DB全くわからないよーという方は今回は以下の画像のように設定しておけば大丈夫です。
(画面から見切れているcommentsやVirtualityなどは何も書かなくて大丈夫です)
スクリーンショット 2019-09-10 13.37.08.png

最後に右下のsaveを押せばテーブルが完成します:clap:

データを入れます

今回はDBからデータを取ってこれたーってとこまでなのでとりあえず1レコードだけデータを入れておきましょう。
SQLタブを押して以下のSQLを入力して右下のGoを押すとレコードが入ります!
入ってるかどうかはBrowseタブを押せばわかります。
スクリーンショット 2019-09-10 13.40.40.png

実装

やっとDBにデータを入れて準備ができました。お疲れ様です。
それではKtorのプロジェクトにExposedを入れていきましょう

まずはbuild.gradle(追加箇所だけ抜粋)

build.gradleにExposedを追加します。下のやつはmysqlを使うときに必要なやーつです。

build.gradle
dependencies {
    compile "org.jetbrains.exposed:exposed:0.16.1"
    compile "mysql:mysql-connector-java:5.1.46"
}

DBに接続する

Application.ktに以下を追加します

Application.kt
fun initDB() {
    val user = "root"
    val pass = "root"
    val url = "jdbc:mysql://localhost:8889/ExposedSample?useSSL=false"
    val driver = "com.mysql.jdbc.Driver"
    Database.connect(url = url, driver = driver, user = user, password = pass)
}

これを呼ぶだけでDBに接続できます:clap:
MAMPのphpmyadminではユーザーとパスワードはroot(設定とか変えてなければ)なはずなのでrootに。
urlはjdbc:mysql://DBサーバーのipアドレス:ポート/DB名?オプションとなっています。
MAMPはデフォルトではMySQLのポート番号が8889になっています。MAMPのpreferenceから自分で変更している場合はこちらもそれに合わせてください。
useSSL=falseはつけないとWARNの警告が出るのでとりあえずつけました。

今回はこのinitDB()。こんな感じでmain関数の中で呼んでしまいましょう。
こうするとIntelliJでRunしたタイミングでDBに接続されます。

Applicatoin.kt
fun main(args: Array<String>): Unit = run {
    initDB()
    io.ktor.server.netty.EngineMain.main(args)
}

DBからデータを取ってくる

さあここまででDBへ接続することができました。
ここからDBからデータをselectしてきてみたいと思います。

Exposedを使ってDBからデータを取ってくる方法は
・DSL
・DAO
の2種類あるようです。
SQLに近い方が個人的には扱いやすいので今回はDSLを使おうと思います。

まず以下のようなobjectを追加します。

Application.kt
    object Table1 : Table() {
        val name = varchar("name", length = 255)
    }

このobjectの名前はデータを取ってくるテーブルの名前と一致させるようにしてください。
またvarcharの引数のnameもTable1で設定したカラム名と一致させてください。
いずれも一致していないと例外が発生してしまいます。
(lengthは50とかにしても普通に動くので一致していなくても平気です。ですがわざわざDBで行なった設定と違う値を設定する必要もないかと思います。)
もしname以外にも取ってきたかったらここに追加すれば取ってくることができます。

それでは取ってくるところの実装です。
これを書いてlocalhost:8080にアクセスしてtestNameと表示されたら成功です。

Application.kt
@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    routing {
        get("/") {
            var name = ""
            transaction {
                val result = Table1.selectAll()
                result.forEach { index, resultRow ->
                    name += resultRow[Table1.name]
                    //↓複数ある時にカンマ区切りで表示するため
                    if (result.count() - 1 != index) name += ","
                }
            }
            call.respondText { "$name" }
        }
    }
}

まずtransaction{}ですが、これは公式にall SQL statements should be placed inside a transactionと書かれているのでSELECTなりSQLを発行するときは必ずこれで囲う必要があります。
次にTable1.selectAll()でTable1から全レコードを取ってきます。今回は1レコードしかデータを準備してないので、Allといっても1つしか取れません。
selectAllをするとQueryという型の変数が戻ってきます。このQueryはIterableを継承しているのでforEachで回すことができ、回すとResultRow型の変数が取れます
ResultRowから欲しいカラムの値を取得するには上記のようにit[Table1.name]といった感じで取れます。it["name"]ではないので気をつけてください。

最後にいつものcall.respondText{}で出力しています。

バラバラにApplication.ktを書いていったので分かりづらいと思いますので、最後にApplication.ktの全体を載せておきます。

Application.kt
package com.example

import io.ktor.application.*
import io.ktor.response.*
import io.ktor.request.*
import io.ktor.routing.get
import io.ktor.routing.routing
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction

fun main(args: Array<String>): Unit = run {
    initDB()
    io.ktor.server.netty.EngineMain.main(args)
}

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    routing {
        get("/") {
            var name = ""
            transaction {
                val result = Table1.selectAll()
                result.forEachIndexed { index, resultRow ->
                    name += resultRow[Table1.name]
                    if (result.count() - 1 != index) name += ","
                }
            }
            call.respondText { "$name" }
        }
    }
}

fun initDB() {
    val user = "root"
    val pass = "root"
    val url = "jdbc:mysql://localhost:8889/ExposedSample?useSSL=false"
    val driver = "com.mysql.jdbc.Driver"
    Database.connect(url = url, driver = driver, user = user, password = pass)
}

object Table1 : Table() {
    val name = varchar("name", length = 50)
}

終わりに

今回はKtor + Exposedを使ってDB接続をしてSELECTでデータを取ってきてみました。
KtorやExposedはまだまだSpringとかに比べたら情報が少ないと思うので、少しでもこの記事がお役に立てたら嬉しいです。
もし間違いなどがありましたらコメントや編集リクエストしていただけたらと思います。

最後までお読みいただきありがとうございました。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away