文档
演练
事务

事务

数据库事务是指一系列读/写操作,这些操作保证要么全部成功,要么全部失败。

示例使用以下 prisma 模式

model Post {
  id        String   @id @default(cuid())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  published Boolean
  title     String
  content   String?
 
  comments Comment[]
}
 
model Comment {
  id        String   @id @default(cuid())
  createdAt DateTime @default(now())
  content   String
 
  post   Post   @relation(fields: [postID], references: [id])
  postID String
}

示例

一个简单的交易可能如下所示。只需省略 Exec(ctx),并将 Prisma 调用提供给 client.Prisma.Transaction

// create two posts at once and run in a transaction
 
firstPost := client.Post.CreateOne(
  db.Post.Published.Set(true),
  db.Post.Title.Set("First Post"),
).Tx()
 
secondPost := client.Post.CreateOne(
  db.Post.Published.Set(false),
  db.Post.Title.Set("Second Post"),
).Tx()
 
if err := client.Prisma.Transaction(firstPost, secondPost).Exec(ctx); err != nil {
  panic(err)
}
 
log.Printf("first post result: %+v", firstPost.Result())
log.Printf("second post result: %+v", secondPost.Result())

多个事务

如果您有很多事务项或需要动态构建事务,可以使用 PrismaTransaction 类型

// create two posts at once and run in a transaction
var txns []db.PrismaTransaction
 
for _, title := range []string{"First Post", "Second Post"} {
  txn := client.Post.CreateOne(
    db.Post.Published.Set(true),
    db.Post.Title.Set(title),
  ).Tx()
  txns = append(txns, txn)
}
 
if err := client.Prisma.Transaction(txns...).Exec(ctx); err != nil {
  panic(err)
}

设置外键关系

设置外键关系时,您需要设置相关记录的 ID。例如,要创建包含多个评论的帖子,您需要执行以下操作

postID := "12345"
 
txns := []db.PrismaTransaction{
  client.Post.CreateOne(
    db.Post.Published.Set(true),
    db.Post.Title.Set("First Post"),
    db.Post.ID.Set(postID),
  ).Tx(),
  client.Comment.CreateOne(
    db.Comment.Content.Set("First comment"),
    db.Comment.Post.Link(
      db.Post.ID.Equals(postID),
    ),
  ).Tx(),
  client.Comment.CreateOne(
    db.Comment.Content.Set("Second comment"),
    db.Comment.Post.Link(
      db.Post.ID.Equals(postID),
    ),
  ).Tx(),
}
 
if err := client.Prisma.Transaction(txns...).Exec(ctx); err != nil {
  panic(err)
}

失败场景

假设我们在数据库中有一条帖子记录

{
  "id": "123",
  "title": "Hi from Prisma"
}
// this will fail, since the record doesn't exist...
a := client.Post.FindUnique(
  db.Post.ID.Equals("does-not-exist"),
).Update(
  db.Post.Title.Set("new title"),
).Tx()
 
// ...so this should be roll-backed, even though itself it would succeed
b := client.Post.FindUnique(
  db.Post.ID.Equals("123"),
).Update(
  db.Post.Title.Set("New title"),
).Tx()
 
if err := client.Prisma.Transaction(b, a).Exec(ctx); err != nil {
  // this err will be non-nil and the transaction will rollback,
  // so nothing will be updated in the database
  panic(err)
}