KotlinからExposedを使ってSQLiteを操作する

# 追記
[こちらのコメント](https://qiita.com/mayoneko/items/a833baac5755a6478945#comment-f9f1648b44cdf0c2fa03)に書かれているように、[この記事のハマったところ](https://qiita.com/mayoneko/items/a833baac5755a6478945#%E3%81%AF%E3%81%BE%E3%81%A3%E3%81%9F%E3%81%A8%E3%81%93%E3%82%8D)は、現在は[Exposedの公式FAQ](https://github.com/JetBrains/Exposed/wiki/FAQ#q-sqlite3-fails-with-the-error-transaction-attempt-0-failed-sqlite-supports-only-transaction_serializable-and-transaction_read_uncommitted)にて言及されているようです。
Kotlinに関する情報が増えてきたことで、ますますとっつきやすい言語になっているという実感があります！
以上追記終わり！


# はじめに
KotlinでSQLを操作するととても気持ちいいという噂を聞きまして、実証すべくお手軽なSQLiteを用いてやってみることにしました。
今回はローカルに置かれたSQLiteを使います。

# 環境
- IntelliJIDEA 2017.3
- Kotlin 1.2.0
- exposed 0.9.1

# Gradle
```
buildscript {
    ext.kotlin_version = '1.2.0'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath group: 'org.xerial', name: 'sqlite-jdbc', version: "3.21.0"
    }
}

group 'mayoneko'
version '1.0-SNAPSHOT'

apply plugin: 'kotlin'

repositories {
    mavenCentral()
    maven {
        url('https://dl.bintray.com/kotlin/exposed/')
    }
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile 'org.jetbrains.exposed:exposed:0.9.1'
    compile 'org.slf4j:slf4j-simple:+' //ないと怒られるから入れておくけどなくても動く
    runtime group: 'org.xerial', name: 'sqlite-jdbc', version: '3.21.0'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
```

# ソースコード
```kotlin

import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SchemaUtils.create
import org.jetbrains.exposed.sql.transactions.transaction
import java.sql.Connection

object Members: Table() {
    val id=integer("id").autoIncrement().primaryKey()
    val name=text("name")
    val old=integer("old")
    val hoge=bool("hoge")
    val count=integer("count")
}

fun main(args: Array<String>) {
    Database.connect("jdbc:sqlite:C:/Users/僕の名前/Documents/KotlinFolder/Kotlin-SQLite-test/test.sqlite", "org.sqlite.JDBC")
    transaction(transactionIsolation = Connection.TRANSACTION_SERIALIZABLE, repetitionAttempts = 3) {
        create(Members)
        Members.insert {
            it[name]="taro"
            it[old]=22
            it[hoge]=false
            it[count]=2
        }
        Members.insert {
            it[name]="hanako"
            it[old]=21
            it[hoge]=false
            it[count]=5
        }
        Members.insert {
            it[name]="hogeko"
            it[old]=58
            it[hoge]=true
            it[count]=10
        }
        Members.insert {
            it[name]="hogeo"
            it[old]=19
            it[hoge]=true
            it[count]=15
        }
        Members.insert {
            it[name]="goro"
            it[old]=29
            it[hoge]=false
            it[count]=3
        }
        Members.insert {
            it[name]="hogejiro"
            it[old]=37
            it[hoge]=true
            it[count]=7
        }
        for (line in Members.selectAll()){
            for (data in line.data){
                print(data)
            }
            println()
        }
        Members.select {
            Members.hoge.eq(true)
        }.forEach {
            println("${it[Members.name]}は${it[Members.old]}歳のhogeです")
        }
    }
}
```

# はまったところ
- サンプル通りに`transaction`を引数なしで指定すると、エラーが出る。
    - SQLiteは`TRANSACTION_SERIALIZABLE`か`TRANSACTION_READ_UNCOMMITTED`でしか動かない
    - `transaction`関数の引数の一つ目に`Connection.TRANSACTION_SERIALIZABLE`を指定する
    - デフォルトは`Connection.TRANSACTION_REPEATABLE_READ`
- `transaction`関数の二つ目の引数が分からない
    - `repetitionAttempts`という`Int`型の引数を取るらしい。
    - [Exposedのソースコード](https://github.com/JetBrains/Exposed/blob/master/src/main/kotlin/org/jetbrains/exposed/sql/transactions/ThreadLocalTransactionManager.kt#L55)に書いてある`3`をよく分からないままに入れたらうまく動いた。

# 発展
kotlinx.htmlのライブラリと一緒に使うとtableの表示なんかが楽しく書けるので、そっちもやってみました。サーバーにはSparkFrameworkを利用しています。

ソースコード

```kotlin

import spark.Spark.get
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils.create
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
import java.sql.Connection

object Student : Table("student") {
    val id = integer("student_id").autoIncrement().primaryKey()
    val name = varchar("name", 50)
    val grade = integer("grade")
}

fun main(args: Array<String>) {

    Database.connect("jdbc:sqlite:C:/Users/僕の名前/Documents/KotlinFolder/Kotlin-HTML-test/test.sqlite", "org.sqlite.JDBC")
    transaction(transactionIsolation = Connection.TRANSACTION_SERIALIZABLE, repetitionAttempts = 3) {
        create(Student)
        Student.insert {
            it[name] = "taro"
            it[grade] = 3
        }
        Student.insert {
            it[name] = "hanako"
            it[grade] = 2
        }
        Student.insert {
            it[name] = "hogeo"
            it[grade] = 1
        }
        val text = createHTML().html {
            head {
                meta(charset = "UTF-8")
                title {
                    +"Kotlin-HTML-test"
                }
                style {
                    +"table,td{border:solid 1px #000000; border-collapse:collapse;}"
                }
            }
            body {
                table {
                    for (line in Student.selectAll()) {
                        tr {
                            for (content in line.data) {
                                td { +"$content" }
                            }
                        }
                    }
                }
            }
        }
        val index = createHTML().html {
            head {
                meta(charset = "UTF-8")
                title { +"こんにちは" }
            }
            body {
                a(href = "/hello") { +"こちらへ" }
            }
        }

        get("/") { request, response ->
            index
        }
        get("/hello") { request, response ->
            text
        }
    }
}
```

楽しいKotlin

# 参考にしたサイト
- [Exposedの使い方 &#8211; Javaビーム研究所](http://blog.orekyuu.net/?p=484)
- [kotlin SQL Framework Exposed を使ってDB接続してみた - So Far, So Tech](https://ver-1-0.net/2017/02/08/kotlin-db-connect-by-exposed/)
- [FlywayのサンプルをSQLiteでやってみる](https://qiita.com/takaki@github/items/d8831694eef6ce4da1e9)
- [3. トランザクション処理 (3) | TECHSCORE(テックスコア)](http://www.techscore.com/tech/Java/JavaEE/JDBC/3-3/)
- [JAVAでSQLiteを使ってみた - MAXIMUM.PROの日記](http://d.hatena.ne.jp/MAXIMUM-PRO/20111029/1319845901)
- [java - JPA+SQLite problem - Stack Overflow](https://stackoverflow.com/questions/906241/jpasqlite-problem)