0Pricing
Scala for Backend Engineering & Functional Programming · Урок

Вставка и обновление

Функционально записывайте данные.

«Вставка и обновление» — бесплатный урок Scala for Backend Engineering & Functional Programming на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Scala for Backend Engineering & Functional Programming, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.

Update0 для операций записи

Для записи используется тот же интерполятор sql, но вместо .query вызывается .update, возвращающий Update0.

Выполнение .run для Update0 возвращает ConnectionIO[Int] — количество затронутых строк.

import doobie.implicits._

def insert(name: String, age: Int): ConnectionIO[Int] =
  sql"insert into users (name, age) values ($name, $age)".update.run

Количество затронутых строк

Значение Int, возвращаемое .run, — это количество обновлений JDBC. Для UPDATE или DELETE оно показывает, сколько строк соответствует условию.

По этому значению можно выбрать дальнейшее действие, например обнаружить UPDATE, которому не соответствует ни одна строка.

def deactivate(id: Long): ConnectionIO[Int] =
  sql"update users set active = false where id = $id".update.run

Возврат сгенерированных ключей

Чтобы получить автоматически сгенерированный первичный ключ, используйте .withUniqueGeneratedKeys, указав столбцы, которые возвращает база данных.

Операция выполняет вставку и считывает сгенерированные значения за один обмен с сервером.

def insertReturningId(name: String, age: Int): ConnectionIO[Long] =
  sql"insert into users (name, age) values ($name, $age)"
    .update
    .withUniqueGeneratedKeys[Long]("id")

Возврат всей строки

Можно одновременно вернуть несколько сгенерированных или заданных по умолчанию столбцов, считав их в кортеж или класс-кейс.

Это особенно удобно для получения серверных значений по умолчанию, например временных меток, сразу после вставки.

case class User(id: Long, name: String, createdAt: java.time.Instant)

def create(name: String): ConnectionIO[User] =
  sql"insert into users (name) values ($name)"
    .update
    .withUniqueGeneratedKeys[User]("id", "name", "created_at")

Класс Update для пакетных операций

Update[A] — это подготовленная параметризованная инструкция, которую можно выполнять многократно. Вы один раз задаёте SQL со знаками подстановки ?, а затем передаёте значения типа A.

Она создаётся из строки SQL и экземпляра Write[A].

val ins: Update[(String, Int)] =
  Update[(String, Int)]("insert into users (name, age) values (?, ?)")

Эффективные пакетные вставки

updateMany отправляет всю коллекцию одним пакетом JDBC, что значительно быстрее последовательного выполнения отдельных вставок.

Метод возвращает общее количество затронутых строк. Используйте его при загрузке большого количества строк за один раз.

val rows = List(("Ada", 36), ("Linus", 54))

val batch: ConnectionIO[Int] = ins.updateMany(rows)

Пакетная вставка с ключами

Update также может возвращать сгенерированные ключи для пакета через updateManyWithGeneratedKeys, выдавая по одной строке на каждую вставленную запись.

Это сочетает массовую загрузку с чтением присвоенных идентификаторов.

import fs2.Stream

val keyed: Stream[ConnectionIO, Long] =
  ins.updateManyWithGeneratedKeys[Long]("id")(rows)

Операции upsert с ON CONFLICT

Специфичные для базы данных операции upsert без проблем работают через Doobie. В PostgreSQL вы обычно пишете insert ... on conflict ... do update как обычный SQL.

Doobie лишь связывает параметры; семантику upsert определяет база данных.

def upsert(email: String, name: String): ConnectionIO[Int] =
  sql"""insert into accounts (email, name) values ($email, $name)
         on conflict (email) do update set name = excluded.name"""
    .update.run

Экземпляры Write и значения по умолчанию

Параметры кодируются с помощью типового класса Write[A], который выводится для примитивов, кортежей и классов-кейсов. Для каждого поля нужен экземпляр Put.

Если не включить столбец во вставку, база данных применит его значение DEFAULT — так, например, появляются сгенерированные временные метки.

case class NewUser(name: String, age: Int)

val mk = Update[NewUser](
  "insert into users (name, age) values (?, ?)"
)

Пользовательские сопоставления столбцов с помощью Meta

Чтобы сохранять пользовательский тип, определите Meta[A], сопоставив его с существующим типом столбца с помощью imap (или timap).

Meta обеспечивает и чтение, и запись, поэтому этот тип одинаково работает в запросах и операциях обновления.

import doobie.util.meta.Meta

case class UserId(value: Long)

implicit val uidMeta: Meta[UserId] =
  Meta[Long].imap(UserId.apply)(_.value)

Удаление — тоже операция обновления

Инструкции DELETE также используют .update.run и возвращают количество удалённых строк.

Единообразное представление вставок, обновлений и удалений как Update0 делает API компактным и удобным для композиции.

def purgeInactive: ConnectionIO[Int] =
  sql"delete from users where active = false".update.run

Быстрая проверка

Выберите наиболее эффективный подход.

Итоги

Для записи используется .update, создающий Update0; .run возвращает количество затронутых строк, а .withUniqueGeneratedKeys считывает сгенерированные значения.

Для массовых операций Update[A].updateMany эффективно формирует пакет. Для пользовательских типов создаются экземпляры Meta, а upsert — это обычный SQL базы данных с параметрами, связанными Doobie.

Часто задаваемые вопросы

Урок «Вставка и обновление» бесплатный?

Да — полный текст урока «Вставка и обновление» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Scala for Backend Engineering & Functional Programming, подпишись на CoddyKit PRO. Курс Scala for Backend Engineering & Functional Programming содержит 4 уроков всего.

Чему я научусь в уроке «Вставка и обновление»?

Функционально записывайте данные. Ты практикуешь Scala for Backend Engineering & Functional Programming с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Scala for Backend Engineering & Functional Programming?

Предыдущий опыт не требуется. Scala for Backend Engineering & Functional Programming на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Вставка и обновление»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Scala for Backend Engineering & Functional Programming?

Да. Каждый урок Scala for Backend Engineering & Functional Programming включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Подключение через трансактор
  2. Выполнение запросов
  3. Вставка и обновление
  4. Композиция транзакций
← Назад к Scala for Backend Engineering & Functional Programming