Exposedとは?
- JetBrains社が開発しているKotlin製のO/Rマッパー
- DSL(SQLライク)、DAO(軽量)の2つのアクセス方法がある
build.gradle.ktsへの追加
dependencies {
implementation("org.jetbrains.exposed", "exposed-core", "0.39.2")
implementation("org.jetbrains.exposed", "exposed-dao", "0.39.2")
implementation("org.jetbrains.exposed", "exposed-jdbc", "0.39.2")
implementation("mysql:mysql-connector-java:8.0.30")
}
DBの準備
docker-compose.ymlファイルをプロジェクト直下に置く
docker-compose.yml
version: '3'
services:
# MySQL
db:
image: mysql:8.0.30
ports:
- 3306:3306
container_name: mysql_host
environment:
MYSQL_ROOT_PASSWORD: mysql
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- ./docker/db/data:/var/lib/mysql
- ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
- ./docker/db/sql:/docker-entrypoint-initdb.d
- dockerコンテナの起動
docker-compose up -d
create database 、 create table
create database exposed_example;
use exposed_example;
create table member(
id int NOT NULL AUTO_INCREMENT,
name varchar(32) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DSLでデータ操作を実装する
- Tableクラスを継承して、テーブルに対応したオブジェクトを作成する
- Database.connectでDB接続する
- transactionでトランザクションを定義する
- Member.insertでデータを挿入する
- getオペレータで登録結果から指定のカラムの値を取得できる
- Member.selectで任意のレコードを取得できる
- member[Member.name]のようにmapとして値を取り出す
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.transactions.transaction
// Tableクラスを継承したmemberテーブルに対応するMemberオブジェクトを作成する
object Member : Table("member") {
// カラム情報を同じにする
val id = integer("id").autoIncrement()
val name = varchar("name", 32)
}
fun main() {
// DBへの接続
Database.connect(
url = "jdbc:mysql://127.0.0.1:3306/exposed_example",
driver = "com.mysql.cj.jdbc.Driver",
user = "root",
password = "mysql"
)
// トランザクションの定義
transaction {
// ログの追加(任意)
addLogger(StdOutSqlLogger)
// データを挿入する
val id = Member.insert {
it[name] = "Kotlin"
} get Member.id // getオペレータで、登録結果から指定のカラムの値を取得できる
println("Inserted id: $id")
// idが一致する1行を取得する
val member: ResultRow = Member.select(Member.id eq id).single()
// mapとして取り出す
println("id: ${member[Member.id]}")
println("name: ${member[Member.name]}")
}
}
- 出力結果
SQL: INSERT INTO `member` (`name`) VALUES ('Kotlin')
Inserted id: 1
SQL: SELECT `member`.id, `member`.`name` FROM `member` WHERE `member`.id = 1
id: 1
name: Kotlin
DAOでデータ操作を実装する
- IntIdTableクラスを継承したmemberテーブルに対応するMemberTableオブジェクトを作成する
- idを除いたカラム情報を同じにする
- IntEntityクラスを継承したMemberEntityクラスを作成する
- 主キー以外のカラムは、対応するカラムのフィールドにデリゲートする
- newでINSERT文の実行。登録後の値が設定されたEntityを返す
- findByでSELECT文の実行。null許容のMemberEntityが返却される
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.StdOutSqlLogger
import org.jetbrains.exposed.sql.addLogger
import org.jetbrains.exposed.sql.transactions.transaction
// IntIdTableクラスを継承したmemberテーブルに対応するMemberTableオブジェクトを作成する
object MemberTable : IntIdTable("member") {
// idを除いたカラム情報を同じにする
val name = varchar("name", 32)
}
// IntEntityクラスはEntityクラスの子クラスでint型の主キーを持つテーブルで使用する
// EntityはSQLの生成などがラッピングされた関数を持つ
class MemberEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<MemberEntity>(MemberTable)
// 主キー以外のカラムは、対応するカラムのフィールドにデリゲートする
var name by MemberTable.name
}
fun main() {
// DBへの接続
Database.connect(
url = "jdbc:mysql://127.0.0.1:3306/exposed_example",
driver = "com.mysql.cj.jdbc.Driver",
user = "root",
password = "mysql"
)
// トランザクションの定義
transaction {
// ログの追加(任意)
addLogger(StdOutSqlLogger)
// INSERT文の実行 登録後の値が設定されたEntityを返す
val member = MemberEntity.new {
name = "Kotlin"
}
println("Inserted id: ${member.id}")
// 主キー検索する。null許容のMemberEntityクラスが返却される
MemberEntity.findById(member.id)?.let {
println("id: ${it.id}")
println("name: ${it.name}")
}
}
}
- 出力結果
SQL: INSERT INTO `member` (`name`) VALUES ('Kotlin')
Inserted id: 2
id: 2
name: Kotlin
参考
Kotlin サーバーサイドプログラミング実践開発 竹端 尚人
https://www.amazon.co.jp/dp/B091PGXHJY/ref=cm_sw_r_tw_dp_ZAWZHH6DFBC5P3H0P38D