LoginSignup
1
3

More than 1 year has passed since last update.

Kotlin製のO/Rマッパー Exposedを試す

Last updated at Posted at 2022-09-24

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

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3