Wstawianie i aktualizowanie
Będzie Pan/Pani zapisywać dane funkcyjnie.
Wstawianie i aktualizowanie to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Update0 dla operacji zapisu
Operacje zapisu używają tego samego interpolatora sql, ale zamiast .query należy wywołać .update, aby uzyskać Update0.
Wywołanie .run na Update0 zwraca ConnectionIO[Int]: liczbę zmodyfikowanych wierszy.
import doobie.implicits._
def insert(name: String, age: Int): ConnectionIO[Int] =
sql"insert into users (name, age) values ($name, $age)".update.runLiczba zmodyfikowanych wierszy
Wartość Int zwracana przez .run to licznik aktualizacji JDBC. W przypadku UPDATE lub DELETE informuje, ile wierszy spełniło warunek.
Można na jej podstawie sterować przebiegiem programu, na przykład wykrywając aktualizację, która nie znalazła żadnego wiersza.
def deactivate(id: Long): ConnectionIO[Int] =
sql"update users set active = false where id = $id".update.runZwracanie wygenerowanych kluczy
Aby uzyskać automatycznie wygenerowany klucz główny, należy użyć .withUniqueGeneratedKeys, podając nazwy kolumn zwracanych przez bazę danych.
Operacja wykonuje INSERT i odczytuje wygenerowane wartości w ramach jednego żądania.
def insertReturningId(name: String, age: Int): ConnectionIO[Long] =
sql"insert into users (name, age) values ($name, $age)"
.update
.withUniqueGeneratedKeys[Long]("id")Zwracanie całego wiersza
Można jednocześnie zwrócić kilka wygenerowanych lub domyślnych kolumn, odczytując je do krotki albo klasy przypadku.
Jest to przydatne do przechwytywania wartości domyślnych po stronie serwera, takich jak znaczniki czasu, bezpośrednio po wykonaniu INSERT.
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")Klasa Update dla partii
Update[A] to przygotowane, parametryzowane zapytanie, które można wykonywać wielokrotnie. SQL definiuje się raz, używając symboli zastępczych ?, a następnie dostarcza wartości typu A.
Obiekt ten powstaje z ciągu SQL oraz instancji Write[A].
val ins: Update[(String, Int)] =
Update[(String, Int)]("insert into users (name, age) values (?, ?)")Wydajne wstawianie partiami
updateMany wysyła całą kolekcję w jednej partii JDBC, co jest znacznie szybsze niż wykonywanie pojedynczych INSERT-ów w pętli.
Zwraca łączną liczbę zmodyfikowanych wierszy. Należy używać go podczas jednoczesnego ładowania wielu wierszy.
val rows = List(("Ada", 36), ("Linus", 54))
val batch: ConnectionIO[Int] = ins.updateMany(rows)Wstawianie partiami z kluczami
Update może również strumieniować wygenerowane klucze dla partii za pomocą updateManyWithGeneratedKeys, zwracając jeden wiersz dla każdego wstawionego rekordu.
Łączy to masowe ładowanie z odczytywaniem przypisanych identyfikatorów.
import fs2.Stream
val keyed: Stream[ConnectionIO, Long] =
ins.updateManyWithGeneratedKeys[Long]("id")(rows)Upserty z ON CONFLICT
Specyficzne dla bazy danych operacje upsert działają bez problemu za pośrednictwem Doobie. W PostgreSQL należy napisać insert ... on conflict ... do update jako zwykły SQL.
Doobie jedynie wiąże parametry; semantyka upsertu należy do bazy danych.
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.runInstancje Write i wartości domyślne
Parametry są kodowane za pomocą klasy typów Write[A], wyprowadzanej dla typów prostych, krotek i klas przypadków. Każde pole wymaga instancji Put.
Jeśli kolumna zostanie pominięta podczas INSERT, baza danych zastosuje jej DEFAULT, co umożliwia generowanie na przykład znaczników czasu.
case class NewUser(name: String, age: Int)
val mk = Update[NewUser](
"insert into users (name, age) values (?, ?)"
)Niestandardowe mapowania kolumn za pomocą Meta
Aby utrwalać niestandardowy typ, należy zdefiniować Meta[A], mapując go na istniejący typ kolumny za pomocą imap (lub timap).
Obiekt Meta zapewnia zarówno odczyt, jak i zapis, dzięki czemu typ działa zarówno w zapytaniach, jak i w aktualizacjach.
import doobie.util.meta.Meta
case class UserId(value: Long)
implicit val uidMeta: Meta[UserId] =
Meta[Long].imap(UserId.apply)(_.value)DELETE też jest operacją aktualizacji
Instrukcje DELETE również używają .update.run i zwracają liczbę usuniętych wierszy.
Jednolite traktowanie INSERT, UPDATE i DELETE jako Update0 pozwala zachować małe i kompozycyjne API.
def purgeInactive: ConnectionIO[Int] =
sql"delete from users where active = false".update.runSzybkie sprawdzenie
Należy wybrać najwydajniejsze podejście.
Podsumowanie
Operacje zapisu używają .update do utworzenia Update0; .run zwraca liczbę zmodyfikowanych wierszy, a .withUniqueGeneratedKeys odczytuje wygenerowane wartości.
W przypadku operacji masowych Update[A].updateMany wydajnie tworzy partie. Dla niestandardowych typów definiuje się instancje Meta, a upserty są po prostu zwykłym SQL-em bazy danych, którego parametry wiąże Doobie.
Często zadawane pytania
Czy lekcja „Wstawianie i aktualizowanie” jest bezpłatna?
Tak — pełny tekst „Wstawianie i aktualizowanie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Co nauczysz się w „Wstawianie i aktualizowanie”?
Będzie Pan/Pani zapisywać dane funkcyjnie. Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?
Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Wstawianie i aktualizowanie”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?
Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Łączenie za pomocą transaktora
- Wykonywanie zapytań
- Wstawianie i aktualizowanie
- Komponowanie transakcji