データベース

概要

KomapperでデータベースにアクセスするためにはJdbcDatabaseもしくはR2dbcDatabaseのインスタンスが必要です。 ここでは、これらを総称してDatabaseインスタンスと呼びます。

Databaseインスタンスはトランザクションの制御やクエリの実行を担当します。

インスタンスの生成

Databaseインスタンスの生成方法はJDBCを使う場合とR2DBCを使う場合で異なります。

JDBCを使う場合

URLから生成する場合は次のように記述します。

val db: JdbcDatabase = JdbcDatabase("jdbc:h2:mem:example;DB_CLOSE_DELAY=-1")

URLに加えてユーザー名やパスワードを指定する場合は次のように記述します。

val db: JdbcDatabase = JdbcDatabase(
  url = "jdbc:h2:mem:example;DB_CLOSE_DELAY=-1", 
  user = "sa", 
  password = ""
)

javax.sql.DataSourceを指定することもできます。 ただし、その場合はdialectの指定も必要です。

val dataSource: DataSource = ...
val db: JdbcDatabase = JdbcDatabase(
  dataSource = dataSource, 
  dialect = H2JdbcDialect()
)

ダイアレクトも参照ください。

R2DBCを使う場合

URLから生成する場合は次のように記述します。

val db: R2dbcDatabase = R2dbcDatabase("r2dbc:h2:mem:///example;DB_CLOSE_DELAY=-1")

io.r2dbc.spi.ConnectionFactoryOptionsから生成する場合は次のように記述します。 optionsにはConnectionFactoryOptions.DRIVERをキーとする値を含めなければいけません。

val options = ConnectionFactoryOptions.builder()
  .option(ConnectionFactoryOptions.DRIVER, "h2")
  .option(ConnectionFactoryOptions.PROTOCOL, "mem")
  .option(ConnectionFactoryOptions.DATABASE, "example")
  .option(Option.valueOf("DB_CLOSE_DELAY"), "-1")
  .build()
val db: R2dbcDatabase = R2dbcDatabase(options)

io.r2dbc.spi.ConnectionFactoryを指定することもできます。 ただし、その場合はdialectの指定も必要です。

val connectionFactory: ConnectionFactory = ...
val db: R2dbcDatabase = R2dbcDatabase(
  connectionFactory = connectionFactory, 
  dialect = H2R2dbcDialect()
)

ダイアレクトも参照ください。

インスタンスの利用

トランザクションの制御

DatabaseインスタンスのwithTransaction関数でトランザクションを制御します。 withTransaction関数にはトランザクション内で処理したいロジックをラムダ式として渡します。

db.withTransaction {
    ...
}

詳細は トランザクション を参照ください。

クエリの実行

DatabaseインスタンスのrunQuery関数を呼び出すことでクエリを実行できます。

val a = Meta.address
val query: Query<List<Address>> = QueryDsl.from(a)
val result: List<Address> = db.runQuery(query)

DatabaseインスタンスがR2dbcDatabaseの場合でクエリの型がorg.komapper.core.dsl.query.FlowQueryのとき、flowQuery関数を実行できます。

val a = Meta.address
val query: FlowQuery<Address> = QueryDsl.from(a)
val flow: Flow<Address> = db.flowQuery(query)

データベースへのアクセスはflowQuery関数から返されるFlowインスタンスを利用したときに初めて行われます。

クエリの構築については クエリ を参照ください。

低レベルAPIの実行

Query DSL のAPIが要件に合わない場合、低レベルAPIを直接利用できます。

JDBCのAPIを直接利用するには、JdbcDatabaseインスタンスからいくつかのプロパティと関数を呼び出してjava.sql.Connectionを取得します。

val db: JdbcDatabase = ...
db.config.session.useConnection { con: java.sql.Connection ->
    val sql = "select employee_name from employee where employee_id = ?"
    con.prepareStatement(sql).use { ps ->
        ps.setInt(1, 10)
        ps.executeQuery().use { rs ->
            if (rs.next()) {
                println(rs.getString(1))
            }
        }
    }
}

同様に、R2DBCのAPIを直接利用するにはR2dbcDatabaseインスタンスから いくつかのプロパティと関数を呼び出してio.r2dbc.spi.Connectionを取得します。

val db: R2dbcDatabase = ...
db.config.session.useConnection { con: io.r2dbc.spi.Connection ->
    val sql = "select employee_name from employee where employee_id = ?"
    val statement = con.createStatement(sql)
    statement.bind(0, 10)
    statement.execute().collect { result ->
        result.map { row -> row.get(0, String::class.java) }.collect {
            println(it)
        }
    }
}
最終更新 May 4, 2022: Rename dialects (55d344f)