ORM для Kotlin: сравнение и примеры (Exposed, Ktorm, Hibernate)

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

ORM для Kotlin: сравнение и примеры

При разработке на Kotlin выбор подходящей ORM (Object-Relational Mapping) — ключевой этап, влияющий на производительность, читаемость кода и удобство поддержки. В этой статье мы сравним три популярных решения: Exposed (официальная библиотека JetBrains), Ktorm (лёгкая DSL-ориентированная ORM) и Hibernate (классический тяжеловес). Разберём их сильные стороны, особенности и приведём рабочие примеры.

1. Exposed — выбор JetBrains

Exposed — это ORM, разработанная специально для Kotlin компанией JetBrains. Она предлагает два подхода: DSL (типобезопасный) и DAO (Data Access Objects). Основное преимущество — полная интеграция с языком: таблицы описываются как объекты Kotlin, запросы проверяются на этапе компиляции.

Пример (DSL-подход):

import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction

object Users : Table() {
    val id = integer("id").autoIncrement()
    val name = varchar("name", 50)
    val email = varchar("email", 100).uniqueIndex()
    override val primaryKey = PrimaryKey(id)
}

fun main() {
    Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver")
    transaction {
        SchemaUtils.create(Users)
        Users.insert {
            it[name] = "Иван"
            it[email] = "ivan@example.com"
        }
        val result = Users.selectAll().map {
            "${it[Users.name]} - ${it[Users.email]}"
        }
        println(result) // [Иван - ivan@example.com]
    }
}

Особенности:

  • Типобезопасные запросы (меньше ошибок runtime).
  • Нет необходимости в рефлексии (быстрее, чем Hibernate).
  • Поддержка миграций через exposed-migration.
  • Не требует настройки XML или аннотаций — всё в коде.

2. Ktorm — лёгкость и гибкость

Ktorm — это минималистичная ORM, которая использует Kotlin DSL для построения SQL-запросов. В отличие от Exposed, она не генерирует SQL автоматически, а позволяет писать запросы почти как на чистом SQL, но с проверкой типов.

Пример:

import me.liuwj.ktorm.database.Database
import me.liuwj.ktorm.entity.*
import me.liuwj.ktorm.schema.*

interface User : Entity<User> {
    companion object : Entity.Factory<User>()
    val id: Int
    val name: String
    val email: String
}

object Users : Table<User>("users") {
    val id = int("id").primaryKey().bindTo { it.id }
    val name = varchar("name").bindTo { it.name }
    val email = varchar("email").bindTo { it.email }
}

fun main() {
    val database = Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver")
    database.sequenceOf(Users).toList() // Получить всех пользователей
    // Вставка:
    val user = User {
        name = "Петр"
        email = "petr@example.com"
    }
    database.users.add(user)
}

Особенности:

  • Максимально близок к SQL — легко оптимизировать запросы.
  • Небольшой размер JAR (~200 КБ).
  • Поддержка расширений: ktorm-jackson, ktorm-spring-support.
  • Требует явного связывания полей (bindTo), что увеличивает boilerplate.

3. Hibernate — проверенный стандарт

Hibernate — это мощная, но тяжёлая ORM из мира Java. В Kotlin её используют через аннотации или XML. Hibernate предоставляет полный контроль над кэшированием, ленивой загрузкой и генерацией схемы. Однако из-за рефлексии и прокси-классов возможны проблемы с data class (требуется open).

Пример:

import javax.persistence.*

@Entity
@Table(name = "users")
data class User(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Int = 0,
    @Column(nullable = false, length = 50)
    val name: String = "",
    @Column(unique = true, length = 100)
    val email: String = ""
)

fun main() {
    val sessionFactory = // стандартная конфигурация Hibernate
    val session = sessionFactory.openSession()
    session.beginTransaction()
    session.save(User(name = "Анна", email = "anna@example.com"))
    session.transaction.commit()
    val users = session.createQuery("from User", User::class.java).list()
    println(users)
}

Особенности:

  • Богатая экосистема: кэ

Рекомендаций