SQL
Kotlin
SQLite3
exposed
NCCDay 13

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

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"
}

ソースコード

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_SERIALIZABLETRANSACTION_READ_UNCOMMITTEDでしか動かない
    • transaction関数の引数の一つ目にConnection.TRANSACTION_SERIALIZABLEを指定する
    • デフォルトはConnection.TRANSACTION_REPEATABLE_READ
  • transaction関数の二つ目の引数が分からない
    • repetitionAttemptsというInt型の引数を取るらしい。
    • Exposedのソースコードに書いてある3をよく分からないままに入れたらうまく動いた。

発展

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

ソースコード

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

参考にしたサイト