KotlinでDBアクセスしてみた(原始的な方法、標準ライブラリ、3rdパーティライブラリ)
練習用のテーブル
create table articles( id integer primary key, title varchar(20) not null, author varchar(20), content text not null );
原始的な方法
Javaと同じ方法でゴリゴリ書く。
import java.sql.DriverManager import java.sql.ResultSet import java.sql.Statement import java.sql.Connection fun main(args: Array<String>) { val articles = findAllArticles() println(articles) } fun findAllArticles(): List<Article> { var conn: Connection? = null var statement: Statement? = null var resultSet: ResultSet? = null val articleListBuilder = ImmutableArrayListBuilder<Article>() try { conn = DriverManager.getConnection("jdbc:postgresql://localhost/sample") statement = conn?.createStatement() resultSet = statement?.executeQuery("select * from articles") while(resultSet?.next() ?: false) { articleListBuilder.add(Article( resultSet!!.getLong(1), resultSet!!.getString(2)!!, resultSet!!.getString(3) ?: "", resultSet!!.getString(4)!! )) } } finally { resultSet?.close() statement?.close() conn?.close() } return articleListBuilder.build() } data class Article( val id: Long, val title: String, val author: String, val content: String )
Javaよりは簡単に書ける。チェック例外がないだけでだいぶスッキリするなぁ。
Connection
とかのclose()
はちょっと面倒臭いけど仕方ない。Kotlin標準ライブラリにはCloseable
の拡張関数use
があって、これを使えば自分でクローズ書かなくてもいいんだけど、Connection
とかはCloseable
じゃない。
Kotlin標準ライブラリを使う方法
標準ライブラリかどうかはわからないけど、プロジェクトKotlinの一部として開発されてるパッケージkotlin.jdbc
を使う方法。
使うにはリポジトリからクローンして、クラスパスを通す必要がある。
import kotlin.jdbc.getConnection import kotlin.jdbc.use import kotlin.jdbc.useSql import kotlin.jdbc.iterator fun main(args: Array<String>) { val articles = findAllArticles() println(articles) } fun findAllArticles(): List<Article> { val articleListBuilder = ImmutableArrayListBuilder<Article>() getConnection("jdbc:postgresql://localhost/sample").use { // useSql -> use にリネーム予定 it.createStatement()?.useSql { it.executeQuery("select * from articles").use { it.iterator().forEach { articleListBuilder.add(Article( it.getLong(1), it.getString(2)!!, it.getString(3) ?: "", it.getString(4)!! )) } } } } return articleListBuilder.build() } data class Article( val id: Long, val title: String, val author: String, val content: String )
try-catchもクローズもvar
も消えてイイ感じ。でもそれだけ。
ちなみにStatement
の拡張関数useSql
はuse
にリネーム予定(ちょっと残念なバグがあるらしい)。
サードパーティ製ライブラリを使う方法
KotlinでSQLを意識させないためのサードパーティ製ライブラリがあるので使ってみた。 Exposedっていうライブラリで、一応プロトタイプという位置付け。 軽量さを売りにしてるのかな。もうちょっとカッコよくできそうな感じはする。 あとプロトタイプってことなので、まだまだ機能が充実してないです。
使うためにはリポジトリから引っ張って来て、クラスパスとかを上手いこと設定する。
import kotlin.sql.Database import kotlin.sql.Table import kotlin.sql.integer import kotlin.sql.varchar import kotlin.sql.template fun main(args: Array<String>) { val articles = findAllArticles() println(articles) } fun findAllArticles(): List<Article> { val articleListBuilder = ImmutableArrayListBuilder<Article>() Database("jdbc:postgresql://localhost/sample", "org.postgresql.Driver").withSession { Articles.all().forEach { val (id, title, author) = it articleListBuilder.add(Article( id.toLong(), title, author, "" )) } } return articleListBuilder.build() } object Articles: Table() { val id = integer("id").primaryKey() val title = varchar("title", length = 20) val author = varchar("author", length = 20) val content = varchar("content", length = 3000) val all = template(id, title, author) // 注 } data class Article( val id: Long, val title: String, val author: String, val content: String )
「注」の箇所。ここではselect id, title, author
相当のSQLを構築する元を作ってるんだけど、このtemplate
関数は現状では最大3つの引数しか取れないっぽい。そのため今回の例ではcontent
を取るのを諦めた。その他にはカラムのデータ型が整数値と文字列の2種類しかないなど、作り始めて間もない感じが伝わってきた。
Articles.all().forEach
のブロックの中で、it
(ここではTriple
オブジェクト)の各値を多重宣言を使って各名前にバインドしている。
感想
カッコよくて便利なライブラリを作ろうと思いました。