🦌

[Kotlin] Komapperの複数行INSERT

2022/07/30に公開

はじめに

一度に複数の行を追加したいユースケースはよくあると思います。本記事ではKomapperの複数行INSERTの機能を紹介します。

複数行INSERTのSQL

一昔前までは複数行のINSERTに対応しているデータベースは少なかったのですが、最近は多くのデータベースで対応されています。例えば、H2 Database Engine、MariaDB、MySQL、PostgreSQL、SQL Serverなどでは一度に3行を追加するSQLを次のように記述できます。

insert into address (address_id, street, version) values 
    (16, 'STREET 16', 0), 
    (17, 'STREET 17', 0), 
    (18, 'STREET 18', 0)

Komapperが対応しているデータベースの中では唯一Oracle Databaseだけが上記のSQLに非対応で次のような固有のSQLが必要です。

insert all 
    into address (address_id, street, version) values (16, 'STREET 16', 0) 
    into address (address_id, street, version) values (17, 'STREET 17', 0) 
    into address (address_id, street, version) values (18, 'STREET 18', 0) 
select 1 from dual

複数行INSERTを実行するKotlinコード

Komapperはデータベースの差を吸収する機能(Dialect)を使ってデータベースのサポート状況に応じて異なるSQLを構築できます。アプリケーションではデータベースの違いを意識する必要はなく、上述の複数行INSERTに相当するクエリは全てのデータベースに対し次のように記述できます。

val a = Meta.address
val query = QueryDsl.insert(a).multiple(
    Address(16, "STREET 16", 0),
    Address(17, "STREET 17", 0),
    Address(18, "STREET 18", 0)
)

multiple関数には可変長引数の代わりにListを渡すこともできます。

val a = Meta.address
val addressList = listOf(
    Address(16, "STREET 16", 0),
    Address(17, "STREET 17", 0),
    Address(18, "STREET 18", 0)
)
val query = QueryDsl.insert(a).multiple(addressList)

なお、Addressのエンティティ定義は次のとおりです。

@KomapperEntity
data class Address(
    @KomapperId @KomapperColumn(name = "address_id") val addressId: Int,
    val street: String,
    @KomapperVersion val version: Int
)

バッチINSERTを実行するKotlinコード

複数行INSERTに似た機能としてバッチINSERTがあります。これは内部でJDBCやR2DBCのバッチ機能を使うもので次のように記述できます(multiplebatchに変わっただけ)。

val a = Meta.address
val query = QueryDsl.insert(a).batch(
    Address(16, "STREET 16", 0),
    Address(17, "STREET 17", 0),
    Address(18, "STREET 18", 0)
)

オプションでバッチサイズを変更することもできます。

val a = Meta.address
val query = QueryDsl.insert(a).batch(
    Address(16, "STREET 16", 0),
    Address(17, "STREET 17", 0),
    Address(18, "STREET 18", 0)
).options { 
    it.copy(batchSize = 30)
}

一概には言えませんが、INSERT対象の件数によっては複数行INSERTよりバッチINSERTの方がパフォーマンスが良くなるケースがあるかもしれません。

余談

Domaは複数行INSERTをサポートしていませんが、サポート要望を何度かもらったことがあります(バッチINSERT機能で代替できるので結局サポートしていませんが)。Komapperを作るにあたってはまっさらな状態から作れて気が楽ということもあって最初から盛り込むことにしました。

もっとデータベースごとに差がある部分かと思ったのですが、複数行INSERTの構文がSQL標準になって久しいということもあってかほとんどのデータベースで対応されており想定よりすんなりと実装できました。上述したようにOracle Databaseだけが未対応のようでした。

おわりに

Komapperの複数行INSERTの機能を紹介しました。

参考

ドキュメントです。
https://www.komapper.org/ja/docs/reference/query/querydsl/insert/

Discussion