prisma-client-api-transactionspor prisma

Transactions. Reference when using this Prisma feature.

npx skills add https://github.com/prisma/cursor-plugin --skill prisma-client-api-transactions

Transactions

Execute multiple operations atomically.

Sequential Transactions

Array of operations executed in order:

const [user, post] = await prisma.$transaction([
  prisma.user.create({ data: { email: '[email protected]' } }),
  prisma.post.create({ data: { title: 'Hello', authorId: 1 } })
])

All or nothing

If any operation fails, all are rolled back:

try {
  await prisma.$transaction([
    prisma.user.create({ data: { email: '[email protected]' } }),
    prisma.user.create({ data: { email: '[email protected]' } }) // Duplicate!
  ])
} catch (e) {
  // Both operations rolled back
}

Interactive Transactions

For complex logic and dependent operations:

await prisma.$transaction(async (tx) => {
  // Decrement sender balance
  const sender = await tx.account.update({
    where: { id: senderId },
    data: { balance: { decrement: amount } }
  })
  
  // Check balance
  if (sender.balance < 0) {
    throw new Error('Insufficient funds')
  }
  
  // Increment recipient balance
  await tx.account.update({
    where: { id: recipientId },
    data: { balance: { increment: amount } }
  })
})

Transaction options

await prisma.$transaction(
  async (tx) => {
    // operations
  },
  {
    maxWait: 5000,    // Max wait to acquire lock (ms)
    timeout: 10000,   // Max transaction duration (ms)
    isolationLevel: 'Serializable'  // Isolation level
  }
)

Isolation levels

LevelDescription
ReadUncommittedLowest isolation, can read uncommitted changes
ReadCommittedOnly read committed changes
RepeatableReadConsistent reads within transaction
SerializableHighest isolation, serialized execution

Nested Writes

Automatic transactions for nested operations:

// This is automatically a transaction
const user = await prisma.user.create({
  data: {
    email: '[email protected]',
    posts: {
      create: [
        { title: 'Post 1' },
        { title: 'Post 2' }
      ]
    },
    profile: {
      create: { bio: 'Hello!' }
    }
  }
})

Transaction Client

The tx parameter is a Prisma Client scoped to the transaction:

await prisma.$transaction(async (tx) => {
  // Use tx instead of prisma
  await tx.user.create({ ... })
  await tx.post.create({ ... })
  
  // Can call methods
  const count = await tx.user.count()
})

OrThrow in Transactions

Use with interactive transactions:

await prisma.$transaction(async (tx) => {
  // If not found, throws and rolls back entire transaction
  const user = await tx.user.findUniqueOrThrow({
    where: { id: 1 }
  })
  
  await tx.post.create({
    data: { title: 'New Post', authorId: user.id }
  })
})

Best Practices

Keep transactions short

// Good - only DB operations in transaction
const data = prepareData() // Outside transaction
await prisma.$transaction(async (tx) => {
  await tx.user.create({ data })
})

Handle errors

try {
  await prisma.$transaction(async (tx) => {
    // operations
  })
} catch (e) {
  if (e.code === 'P2002') {
    // Handle unique constraint violation
  }
  throw e
}

Use appropriate isolation

// Default is fine for most cases
await prisma.$transaction(async (tx) => {
  // operations
})

// Use Serializable for strict consistency
await prisma.$transaction(
  async (tx) => { /* operations */ },
  { isolationLevel: 'Serializable' }
)

Sequential vs Interactive

FeatureSequentialInteractive
SyntaxArrayAsync function
Dependent opsNoYes
Conditional logicNoYes
PerformanceBetterMore flexible
Use caseSimple batchComplex logic

NotebookLM Web Importer

Importa páginas web y videos de YouTube a NotebookLM con un clic. Utilizado por más de 200,000 usuarios.

Instalar extensión de Chrome