Ktor - asynchronous Web framework for KotlinでDoma2を使ってデータベースアクセスしてみました。 Ktorの公式サイト上にはデータベースアクセスする方法などが全く無いので、これが正解かどうかはわかりませんが…
build.gradle
- データベースアクセスに必要となるライブラリを追加します
dependencies { kapt 'org.seasar.doma:doma:2.22.0' implementation 'org.seasar.doma:doma:2.22.0' runtime 'org.postgresql:postgresql:42.2.5' implementation 'com.zaxxer:HikariCP:3.3.1' }
- Doma2でkaptが必要になるので、kaptプラグインを追加します
apply plugin: 'kotlin-kapt'
データベースの接続先を定義する
resources/application.conf
にデータベースの接続先などを定義します
database { driverClass = org.postgresql.Driver url = "jdbc:postgresql://localhost:5432/siosio" user = siosio password = siosio }
DomaのConfigクラスを追加する
- トランザクション — Doma 2.0 ドキュメントを参考にシングルトンなコンフィグを作ります
Kotlinなので、object
で作ってsingleton
は@JvmStatic
にしています init
で、HikariCPのDataSourceを作成します
接続先などの情報は、resources/application.conf
からとってきます
@SingletonConfig object DomaConfig : Config { private lateinit var ds: LocalTransactionDataSource fun init(environment: ApplicationEnvironment) { val hikariConfig = HikariConfig() hikariConfig.driverClassName = environment.config.property("database.driverClass").getString() hikariConfig.jdbcUrl = environment.config.property("database.url").getString() hikariConfig.username = environment.config.property("database.user").getString() hikariConfig.password = environment.config.property("database.password").getString() ds = LocalTransactionDataSource(HikariDataSource(hikariConfig)) } override fun getDialect(): Dialect = PostgresDialect() override fun getDataSource(): DataSource { if (::ds.isInitialized.not()) { throw IllegalStateException("database setting is not initialized") } return ds } override fun getTransactionManager(): TransactionManager { return LocalTransactionManager(ds.getLocalTransaction(jdbcLogger)) } @JvmStatic fun singleton(): DomaConfig = DomaConfig }
Moduleの定義タイミングでDataSourceを作成する
DomaConfig#init
を呼び出してDataSourceを作成します
fun Application.module(testing: Boolean = false) { // 省略 DomaConfig.init(environment) routing { user() } }
Domaを使いやすくするヘルパーメソッドを追加する
- Daoの実装クラス(DaoImpl)を取得するメソッドを追加します
transaction
を実行するためのメソッドを追加します
inline fun <reified T> dao(): T { return Thread.currentThread().contextClassLoader .loadClass("${T::class.qualifiedName}Impl") .newInstance() as T } fun <T> PipelineContext<out Any, out Any>.transaction(block: () -> T): T { return DomaConfig.transactionManager.required(block) }
データベースアクセス処理を実装する
- 先程定義した
transaction
メソッドに渡したブロック内でデータベースアクセスを行います - 確認用に登録処理と、登録したデータを一括取得する処理を実装しています
fun Route.user(): Unit { get("/users") { val userList = transaction { dao<UserDao>().findAll() } call.respond(userList) } post("/users") { val user = call.receive(UserEntity::class) transaction { dao<UserDao>().insert(user) } call.respond(HttpStatusCode.Created) } }
アプリケーションを実行して確認してみる
データの登録処理
登録処理を呼び出して、2件データを登録してみます
~ ❮❮❮ curl -H 'Content-Type: application/json' -d '{"name": "hoge"}' -D - http://localhost:8080/users HTTP/1.1 201 Created Content-Length: 0 ~ ❯❯❯ curl -H 'Content-Type: application/json' -d '{"name": "fuga"}' -D - http://localhost:8080/users HTTP/1.1 201 Created Content-Length: 0
データの取得処理
一括取得を呼び出すと登録したデータが返されることが確認できます
~ ❯❯❯ curl -D - http://localhost:8080/users HTTP/1.1 200 OK Content-Length: 72 Content-Type: application/json; charset=UTF-8 [ { "id" : 2, "name" : "hoge" }, { "id" : 3, "name" : "fuga" } ]
データベースの確認
登録した2件のデータが確認できます。ちゃんと動いていますね。
siosio=# select * from users; id | name ----+------ 2 | hoge 3 | fuga (2 rows)