Transactions
A database transaction refers to a sequence of read/write operations that are guaranteed to either succeed or fail as a whole.
The examples use the following prisma schema:
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
}
Example
A simple transaction could look as follows. Just omit the Exec(ctx)
, and provide the Prisma calls
to 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())
Multiple transactions
If you have many transaction items or need to construct a transaction dynamically, you can use the PrismaTransaction
type:
// 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)
}
Setting relations with foreign keys
When setting relations with foreign keys, you have to set the IDs of the related records. For example, to create a post with multiple comments, you would do the following:
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)
}
Failure scenario
Let's say we have one post record in the database:
{
"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)
}