Работа с базами данных в Kotlin: PostgreSQL и MongoDB для начинающих

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

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

Начать курс

Введение в работу с базами данных в Kotlin

Kotlin — современный статически типизированный язык, работающий на JVM, который стремительно набирает популярность благодаря лаконичности и безопасности. Одним из ключевых навыков для любого разработчика является умение взаимодействовать с базами данных. В этой статье мы рассмотрим, как подключаться и выполнять основные операции (CRUD) с двумя самыми популярными типами БД: реляционной PostgreSQL и документо-ориентированной MongoDB.

Мы будем использовать современные библиотеки, максимально адаптированные под идиоматический Kotlin:

  • Exposed — ORM-фреймворк от JetBrains для SQL-баз данных (PostgreSQL, MySQL и др.).
  • KMongo — реактивный ODM-клиент для MongoDB, построенный на корутинах.

Статья рассчитана на начинающих: мы разберём настройку проекта, подключение к БД и простые примеры вставки, чтения, обновления и удаления данных.

1. Настройка проекта и подключение зависимостей

Для начала создайте новый проект Kotlin (например, через IntelliJ IDEA с Gradle или Maven). Добавьте необходимые зависимости в файл build.gradle.kts.

Gradle зависимости для PostgreSQL (Exposed)

dependencies {
    // Exposed
    implementation("org.jetbrains.exposed:exposed-core:0.44.1")
    implementation("org.jetbrains.exposed:exposed-dao:0.44.1")
    implementation("org.jetbrains.exposed:exposed-jdbc:0.44.1")

    // Драйвер PostgreSQL
    implementation("org.postgresql:postgresql:42.7.1")

    // Пул соединений (HikariCP)
    implementation("com.zaxxer:HikariCP:5.1.0")
}

Gradle зависимости для MongoDB (KMongo)

dependencies {
    // KMongo (с корутинами)
    implementation("org.litote.kmongo:kmongo-coroutine:4.11.0")

    // Ktor Client (если нужен реактивный драйвер)
    implementation("org.litote.kmongo:kmongo-async:4.11.0")
}

После синхронизации проекта можно приступать к подключению.

2. Работа с PostgreSQL через Exposed

Exposed предоставляет два подхода: DSL (типобезопасные SQL-запросы) и DAO (объектно-реляционное отображение). Мы рассмотрим DAO — он более интуитивен для новичков.

Подключение к базе данных

import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.transactions.transaction
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource

fun connectToPostgres() {
    val config = HikariConfig().apply {
        jdbcUrl = "jdbc:postgresql://localhost:5432/mydb"
        driverClassName = "org.postgresql.Driver"
        username = "user"
        password = "password"
        maximumPoolSize = 10
    }
    val dataSource = HikariDataSource(config)
    Database.connect(dataSource)
    println("Подключение к PostgreSQL установлено!")
}

Определение таблицы и сущности

import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass

// Определяем таблицу
object UsersTable : IntIdTable("users") {
    val name = varchar("name", 100)
    val email = varchar("email", 255).uniqueIndex()
    val age = integer("age").default(18)
}

// Определяем Entity (DAO)
class UserEntity(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<UserEntity>(UsersTable)

    var name by UsersTable.name
    var email by UsersTable.email
    var age by UsersTable.age
}

CRUD операции

fun performCRUD() {
    transaction {
        // Создание таблицы (если не существует)
        SchemaUtils.create(UsersTable)

        // INSERT
        val newUser = UserEntity.new {
            name = "Иван Петров"
            email = "ivan@example.com"
            age = 25
        }
        println("Создан пользователь с ID: ${newUser.id}")

        // SELECT — все пользователи
        val allUsers = UserEntity.all().toList()
        allUsers.forEach { user ->
            println("${user.id}: ${user.name}, ${user.email}, ${user.age}")
        }

        // UPDATE — изменить возраст
        val userToUpdate = UserEntity.findById(1)
        userToUpdate?.apply {
            age = 30
            flush() // сохраняем изменения
            println("Возраст пользователя ${name} обновлён на $age")
        }

        // DELETE — удалить пользователя
        val userToDelete = UserEntity.findById(2)
        userToDelete?.delete()
        println("Пользователь с ID 2 удалён")
    }
}

Важно: Все операции выполняются внутри блока transaction, который автоматически управляет транзакциями.

3. Работа с MongoDB через KMongo

MongoDB — документная БД, где данные хранятся в формате JSON-подобных документов. KMongo предоставляет типобезопасный API для Kotlin с поддержкой корутин.

Подключение к MongoDB

import org.litote.kmongo.coroutine.coroutine
import org.litote.kmongo.reactivestreams.KMongo
import kotlinx.coroutines.runBlocking

fun connectToMongo() {
    val client = KMongo.createClient("mongodb://localhost:27017")
        .coroutine
    val database = client.getDatabase("testdb")
    println("Подключение к MongoDB установлено! База: ${database.name}")
}

Определение модели данных

import org.bson.codecs.pojo.annotations.BsonId
import org.bson.types.ObjectId

data class User(
    @BsonId val id: ObjectId = ObjectId(),
    val name: String,
    val email: String,
    val age: Int = 18
)

Аннотация @BsonId указывает, что поле id является первичным ключом.

CRUD операции с корутинами

import kotlinx.coroutines.runBlocking
import org.litote.kmongo.coroutine.*

fun performMongoCRUD() = runBlocking {
    val client = KMongo.createClient().coroutine
    val db = client.getDatabase("testdb")
    val usersCollection = db.getCollection<User>()

    // INSERT
    val newUser = User(name = "Анна Смирнова", email = "anna@example.com", age = 28)
    usersCollection.insertOne(newUser)
    println("Документ вставлен с ID: ${newUser.id}")

    // SELECT — найти всех пользователей старше 20 лет
    val filter = User::age gt 20
    val                

Блоги

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