Exposedは、Kotlinからデータベースを操作するためのライブラリで、Kotlinの言語機能を活かしたSQL DSLと軽量ORM機能を提供します。
このライブラリは JetBrains が開発しており、Kotlinバックエンド開発では代表的なデータベースアクセスライブラリの一つです。
JavaエコシステムではHibernateやJPAがよく使われますが、Exposedはそれらとは異なり、SQLに近い感覚で安全にクエリを書ける設計が特徴です。
Exposedの概要
ExposedはKotlinでデータベース操作を行うためのライブラリで、以下の特徴を持っています。
主な特徴
- Kotlin DSLでSQLを構築できる
- 型安全なクエリ記述
- JDBCおよびR2DBCに対応
- 軽量なORM(DAO API)を提供
- トランザクション管理機能
- 複数のRDBMSに対応
対応している主なデータベース
- PostgreSQL
- MySQL
- MariaDB
- SQLite
- H2
- Oracle
- Microsoft SQL Server
つまりExposedは「Kotlinで安全にSQLを書くためのデータベースライブラリ」と言えます。
Exposedの2つのAPI
Exposedには大きく分けて2つの利用方法があります。
- DSL API
- DAO API
それぞれ用途が異なります。
DSL API
DSL APIは、KotlinのDSL構文を利用してSQLを構築する方法です。
SQLに近い形で書くことができ、柔軟なクエリを作成できます。
例
Users
.selectAll()
.where { Users.age greater 20 }
このコードは次のSQLに相当します。
SELECT * FROM users
WHERE age > 20;
DSL APIの特徴
- SQLに近い表現
- 柔軟なクエリ
- パフォーマンス制御しやすい
- 型安全
実務ではDSL APIを中心に使用するケースが多いです。
DAO API
DAO APIは、ORMのようにEntityクラスを通してデータベースを操作する方法です。
Entity例
class User(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<User>(Users)
var name by Users.name
var age by Users.age
}
取得例
User.find { Users.age greater 20 }
新規作成
User.new {
name = "Taro"
age = 25
}
DAO APIはORMに近い書き方になりますが、DSL APIより柔軟性はやや低くなります。
また、DAO APIはJDBC接続でのみ利用可能です。
Exposedの基本構造
Exposedでは次の要素を中心にデータベース操作を行います。
| 要素 | 役割 |
|---|---|
| Table | テーブル定義 |
| Column | カラム定義 |
| Transaction | トランザクション管理 |
| DSL | SQLクエリ |
| DAO | Entity操作 |
テーブル定義
Exposedではテーブル構造をKotlinクラスで定義します。
例
object Users : Table() {
val id = integer("id").autoIncrement()
val name = varchar("name", 50)
val age = integer("age")
override val primaryKey = PrimaryKey(id)
}
このコードは次のSQLテーブルを表します。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
age INT
);
データベース接続
データベース接続は Database.connect() を使用します。
例
Database.connect(
url = "jdbc:h2:mem:test",
driver = "org.h2.Driver"
)
JDBC接続の場合、通常はトランザクションブロック内で操作を行います。
transaction {
// DB操作
}
データ挿入(INSERT)
データを追加する場合は insert を使用します。
transaction {
Users.insert {
it[name] = "Taro"
it[age] = 25
}
}
SQL
INSERT INTO users (name, age)
VALUES ('Taro', 25);
データ取得(SELECT)
全件取得
transaction {
Users.selectAll().forEach {
println(it[Users.name])
}
}
条件検索
Users
.selectAll()
.where { Users.age greater 20 }
データ更新(UPDATE)
transaction {
Users.update({ Users.id eq 1 }) {
it[age] = 30
}
}
SQL
UPDATE users
SET age = 30
WHERE id = 1;
データ削除(DELETE)
transaction {
Users.deleteWhere { Users.id eq 1 }
}
SQL
DELETE FROM users
WHERE id = 1;
JOINクエリ
ExposedではJOINもDSLで記述できます。
例
(Users innerJoin Orders)
.selectAll()
SQL
SELECT *
FROM users
INNER JOIN orders
ON users.id = orders.user_id;
Exposedのメリット
Kotlin DSLによる型安全
ExposedはKotlin DSLでクエリを書くため、コンパイル時に型チェックが行われます。
そのため
- カラム名のミス
- 型不一致
などを防ぐことができます。
SQLに近い記述
DSL APIはSQL構造に近いため、
- クエリの可読性
- SQL理解
を保ったままコードを書くことができます。
軽量でシンプル
HibernateなどのフルORMと比較すると、
- 設定が少ない
- 学習コストが低い
- 動作が軽い
というメリットがあります。
Exposedのデメリット
フルORMではない
Hibernateのような機能は限定的です。
例えば
- 自動JOIN
- キャッシュ
- 高度なエンティティ管理
などは弱い傾向があります。
エコシステムが小さい
JPAと比べると
- 情報量
- サンプル
- 外部ライブラリ
はまだ少なめです。
Kotlinバックエンドでの典型構成
Kotlinサーバー開発では次の構成がよく見られます。
Ktor
↓
Exposed
↓
PostgreSQL
Exposedは特にKotlinネイティブなフレームワークと相性が良いです。
他のORMとの違い
| 技術 | 特徴 |
|---|---|
| JPA | Java標準ORM |
| Hibernate | 高機能ORM |
| MyBatis | SQL中心 |
| Exposed | Kotlin DSL型ORM |
ExposedはSQL DSL + 軽量ORMという中間的な位置にあります。
Exposedが向いているケース
次のようなプロジェクトではExposedが適しています。
- Kotlinバックエンド開発
- SQLを明示的に管理したい
- ORMの自動生成に頼りすぎたくない
- Ktorベースのサーバー
まとめ
ExposedはKotlin向けのデータベースライブラリで、
- SQL DSL
- 軽量ORM
- 型安全
という特徴を持っています。
JavaのORMとは違い、SQLの可視性と柔軟性を重視した設計が特徴です。
そのため、Kotlinバックエンド開発ではKtor + Exposed + PostgreSQLのような構成で使われることが多く、Kotlinネイティブなデータアクセスライブラリとして広く利用されています。
以上、KotlinのExposedについてでした。
最後までお読みいただき、ありがとうございました。










