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.runNumero 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.runRestituire 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.runIstanze 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.runVerifica 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
- Connettersi con un transactor
- Eseguire query
- Inserimenti e aggiornamenti
- Comporre transazioni