0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

Inserimenti e aggiornamenti

Scriva dati in modo funzionale.

Inserimenti e aggiornamenti è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.

Update0 per le scritture

Le scritture usano lo stesso interpolatore sql, ma si chiama .update per ottenere un Update0 invece di .query.

L'esecuzione di .run su un Update0 restituisce una ConnectionIO[Int]: il numero di righe interessate.

import doobie.implicits._

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

Numero di righe interessate

L'Int restituito da .run è il conteggio degli aggiornamenti JDBC. Per un'operazione UPDATE o DELETE indica quante righe hanno soddisfatto la condizione.

È possibile usarlo per determinare, ad esempio, se un aggiornamento non ha trovato alcuna riga.

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

Restituire le chiavi generate

Per ottenere una chiave primaria generata automaticamente, usi .withUniqueGeneratedKeys, specificando i nomi delle colonne restituite dal database.

Questo esegue l'inserimento e legge i valori generati in un solo round trip.

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

Restituire un'intera riga

È possibile restituire contemporaneamente più colonne generate o valorizzate con valori predefiniti, leggendole in una tupla o in una case class.

È particolarmente utile per acquisire subito dopo l'inserimento valori predefiniti dal server, come i timestamp.

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")

La classe Update per i batch

Update[A] è un'istruzione preparata e parametrizzata che può essere eseguita molte volte. Si definisce una volta l'SQL con segnaposto ? e si forniscono valori di tipo A.

Viene costruita a partire da una stringa SQL e da un'istanza Write[A].

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

Inserimenti batch efficienti

updateMany invia un'intera collezione in un unico batch JDBC, molto più velocemente rispetto a un ciclo di singoli inserimenti.

Restituisce il numero totale di righe interessate. Lo usi ogni volta che carica molte righe insieme.

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

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

Inserimento batch con chiavi

Update può anche trasmettere le chiavi generate per un batch tramite updateManyWithGeneratedKeys, restituendo una riga per ogni record inserito.

In questo modo si combinano il caricamento in blocco e la lettura degli identificatori assegnati.

import fs2.Stream

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

Upsert con ON CONFLICT

Gli upsert specifici del database funzionano senza problemi tramite Doobie. In PostgreSQL si scrive insert ... on conflict ... do update come normale SQL.

Doobie si limita ad associare i parametri; la semantica dell'upsert appartiene al database.

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

Istanze Write e valori predefiniti

I parametri vengono codificati con il typeclass Write[A], derivato per tipi primitivi, tuple e case class. Ogni campo richiede un'istanza Put.

Se si omette una colonna dall'inserimento, il database applica il relativo DEFAULT: è così che compaiono i timestamp generati.

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

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

Mapping di colonne personalizzati con Meta

Per rendere persistente un tipo personalizzato, definisca un Meta[A] mappandolo su un tipo di colonna esistente con imap (o timap).

Un Meta fornisce sia la lettura sia la scrittura, quindi il tipo funziona allo stesso modo nelle query e negli aggiornamenti.

import doobie.util.meta.Meta

case class UserId(value: Long)

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

Anche le eliminazioni sono aggiornamenti

Anche le istruzioni DELETE usano .update.run e restituiscono il numero di righe rimosse.

Trattare in modo uniforme inserimenti, aggiornamenti ed eliminazioni come Update0 mantiene l'API ridotta e componibile.

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

Verifica rapida

Scelga l'approccio più efficiente.

Riepilogo

Le scritture usano .update per produrre un Update0; .run restituisce le righe interessate e .withUniqueGeneratedKeys legge i valori generati.

Per le operazioni in blocco, Update[A].updateMany esegue il batching in modo efficiente. I tipi personalizzati ricevono istanze Meta e gli upsert sono semplici istruzioni SQL del database, con parametri associati da Doobie.

Domande Frequenti

La lezione «Inserimenti e aggiornamenti» è gratuita?

Sì — il testo completo di «Inserimenti e aggiornamenti» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 4 lezioni in totale.

Cosa imparerò in «Inserimenti e aggiornamenti»?

Scriva dati in modo funzionale. Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?

Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Inserimenti e aggiornamenti»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?

Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Connettersi con un transactor
  2. Eseguire query
  3. Inserimenti e aggiornamenti
  4. Comporre transazioni
← Torna a Scala for Backend Engineering & Functional Programming