Inserções e atualizações
Grave dados funcionalmente.
Inserções e atualizações é uma aula grátis de Scala for Backend Engineering & Functional Programming no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Scala for Backend Engineering & Functional Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.
Update0 para gravações
As gravações usam o mesmo interpolador sql, mas chamam .update para obter um Update0 em vez de .query.
Executar .run em um Update0 retorna um ConnectionIO[Int]: o número de linhas afetadas.
import doobie.implicits._
def insert(name: String, age: Int): ConnectionIO[Int] =
sql"insert into users (name, age) values ($name, $age)".update.runContagens de linhas afetadas
O Int retornado por .run é a contagem de atualizações do JDBC. Para um UPDATE ou DELETE, ele informa quantas linhas corresponderam.
Você pode usar esse valor para tomar decisões e detectar, por exemplo, uma atualização que não correspondeu a nenhuma linha.
def deactivate(id: Long): ConnectionIO[Int] =
sql"update users set active = false where id = $id".update.runRetornando chaves geradas
Para obter uma chave primária gerada automaticamente, use .withUniqueGeneratedKeys, informando os nomes das colunas retornadas pelo banco de dados.
Isso executa a inserção e lê os valores gerados em uma única viagem de ida e volta.
def insertReturningId(name: String, age: Int): ConnectionIO[Long] =
sql"insert into users (name, age) values ($name, $age)"
.update
.withUniqueGeneratedKeys[Long]("id")Retornando uma linha inteira
Você pode retornar várias colunas geradas ou definidas por padrão de uma só vez, lendo-as em uma tupla ou classe de caso.
Isso é ótimo para capturar valores padrão definidos pelo servidor, como marcas de tempo, logo após a inserção.
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")A classe Update para lotes
Update[A] é uma instrução preparada e parametrizada que pode ser executada muitas vezes. Você define o SQL uma vez, usando marcadores ?, e fornece valores do tipo A.
Ela é construída a partir de uma cadeia de caracteres SQL e de uma instância de Write[A].
val ins: Update[(String, Int)] =
Update[(String, Int)]("insert into users (name, age) values (?, ?)")Inserções em lote eficientes
updateMany envia uma coleção inteira em um único lote JDBC, muito mais rápido do que repetir inserções individuais.
Ele retorna o número total de linhas afetadas. Use-o sempre que carregar muitas linhas de uma só vez.
val rows = List(("Ada", 36), ("Linus", 54))
val batch: ConnectionIO[Int] = ins.updateMany(rows)Inserção em lote com chaves
Update também pode transmitir chaves geradas para um lote por meio de updateManyWithGeneratedKeys, retornando uma linha para cada registro inserido.
Isso combina o carregamento em massa com a leitura dos identificadores atribuídos.
import fs2.Stream
val keyed: Stream[ConnectionIO, Long] =
ins.updateManyWithGeneratedKeys[Long]("id")(rows)Upserts com ON CONFLICT
Os upserts específicos de cada banco funcionam normalmente por meio do Doobie. No PostgreSQL, você escreve insert ... on conflict ... do update como SQL normal.
O Doobie apenas associa os seus parâmetros; a semântica do upsert pertence ao banco de dados.
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.runInstâncias de gravação e valores padrão
Os parâmetros são codificados com a classe de tipos Write[A], derivada para tipos primitivos, tuplas e classes de caso. Cada campo precisa de uma instância de Put.
Se você omitir uma coluna da inserção, o banco de dados aplicará seu valor DEFAULT, que é a forma como aparecem as marcas de tempo geradas.
case class NewUser(name: String, age: Int)
val mk = Update[NewUser](
"insert into users (name, age) values (?, ?)"
)Mapeamentos personalizados de colunas com Meta
Para persistir um tipo personalizado, defina um Meta[A] mapeando-o para um tipo de coluna existente com imap (ou timap).
Um Meta fornece tanto leitura quanto gravação, portanto o tipo funciona igualmente em consultas e atualizações.
import doobie.util.meta.Meta
case class UserId(value: Long)
implicit val uidMeta: Meta[UserId] =
Meta[Long].imap(UserId.apply)(_.value)Exclusões também são atualizações
As instruções DELETE também usam .update.run e retornam a quantidade de linhas removidas.
Tratar inserções, atualizações e exclusões uniformemente como Update0 mantém a API pequena e combinável.
def purgeInactive: ConnectionIO[Int] =
sql"delete from users where active = false".update.runVerificação rápida
Escolha a abordagem mais eficiente.
Recapitulação
As gravações usam .update para produzir um Update0; .run retorna as linhas afetadas e .withUniqueGeneratedKeys lê os valores gerados.
Para operações em massa, Update[A].updateMany cria lotes com eficiência. Os tipos personalizados recebem instâncias de Meta, e os upserts são apenas SQL normal do banco de dados, com os parâmetros associados pelo Doobie.
Perguntas Frequentes
A aula “Inserções e atualizações” é grátis?
Sim — o texto completo de “Inserções e atualizações” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Scala for Backend Engineering & Functional Programming, atualize para CoddyKit PRO. O curso de Scala for Backend Engineering & Functional Programming inclui 4 aulas no total.
O que vou aprender em “Inserções e atualizações”?
Grave dados funcionalmente. Você pratica Scala for Backend Engineering & Functional Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Scala for Backend Engineering & Functional Programming?
Nenhuma experiência prévia é necessária. Scala for Backend Engineering & Functional Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Inserções e atualizações”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Scala for Backend Engineering & Functional Programming?
Sim. Cada aula de Scala for Backend Engineering & Functional Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Conectando com um transator
- Executando consultas
- Inserções e atualizações
- Compondo transações