0Pricing
Scala for Backend Engineering & Functional Programming · 课时

插入与更新

以函数式方式写入数据。

插入与更新 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。

用于写入的 Update0

写入操作同样使用sql插值器,但需要调用.update来获取Update0,而不是调用.query。

对Update0运行.run会返回ConnectionIO[Int],表示受影响的行数。

import doobie.implicits._

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

受影响的行数

.run返回的Int就是 JDBC 更新计数。对于 UPDATE 或 DELETE,它表示匹配了多少行。

您可以根据这个值进行分支处理,例如检测更新是否没有匹配任何行。

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)

使用 ON CONFLICT 执行插入或更新

通过 Doobie 使用数据库特定的插入或更新操作完全没有问题。在 PostgreSQL 中,您可以像平常一样使用insert ... on conflict ... do update编写 SQL。

Doobie 只负责绑定参数;插入或更新的语义由数据库决定。

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 自定义列映射

要持久化自定义类型,请使用imap(或timap)将其映射到现有列类型,并定义Meta[A]。

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实例,而插入或更新操作只是由 Doobie 绑定参数的普通数据库 SQL。

常见问题解答

「插入与更新」课时是免费的吗?

是的 — 「插入与更新」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。

「插入与更新」这节课中我会学到什么?

以函数式方式写入数据。 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 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