eduardweb.
Prisma ORMIntermediar#prisma#postgresql#transactions

Prisma transactions — interactive vs batch, când folosesc fiecare

De Ioana Marinescu, 21 apr. 2026 · 3 vizualizări · 2 like-uri

Postat acum 16 ore
typescript
// Exemplu batch
await prisma.$transaction([
  prisma.user.update({ where: { id }, data: { coins: { decrement: 100 } } }),
  prisma.order.create({ data: { userId: id, amount: 100 } }),
  prisma.notification.create({ data: { userId: id, type: "ORDER_CREATED" } }),
]);

// Exemplu interactive
await prisma.$transaction(async (tx) => {
  const user = await tx.user.findUnique({ where: { id }});
  if (!user || user.coins < 100) throw new Error("INSUFFICIENT_COINS");
  await tx.user.update({ where: { id }, data: { coins: user.coins - 100 }});
  await tx.order.create({ data: { userId: id, amount: 100 }});
}, { timeout: 10000 });

Prisma are două tipuri de tranzacții și confuzia între ele a produs majoritatea deadlock-urilor pe care le-am văzut în prod.

Batch transactions (array)

prisma.$transaction([query1, query2, query3]) — Prisma împachetează automat într-o singură BEGIN/COMMIT.

Folosește când:

  • Știi toate query-urile în avans
  • Nu depinzi de rezultatul unuia pentru celălalt
  • Vrei cel mai rapid round-trip posibil

Avantaj: o singură conexiune, o singură tranzacție, zero surprize.

Interactive transactions (callback)

prisma.$transaction(async (tx) => { ... }) — ai control complet, poți ramifica logic.

Folosește când:

  • Ai nevoie de rezultatul unui query pentru următorul
  • Faci validări intermediare
  • Apelezi cod third-party care necesită rollback pe eșec

Atenție: conexiunea e ocupată până termini callback-ul. Dacă faci un fetch extern de 3 secunde în el, blochezi un connection din pool.

Regula mea

Dacă o poți scrie ca batch, o scrii ca batch. Interactive doar când chiar depinzi de rezultat.

Gotcha cu timeout

Default-ul e 5 secunde. Pe Postgres cu lock-uri competitive, poți ajunge să dai timeout real. Setezi explicit:

prisma.$transaction(async (tx) => { ... }, {
  maxWait: 5000,  // cât aștepți în coadă
  timeout: 15000, // cât durează efectiv
  isolationLevel: "Serializable", // dacă chiar ai nevoie
})

Bonus: nu uita de connection pool

La DATABASE_URL adaugă ?connection_limit=20 pe PgBouncer. Default-ul Prisma e calculat greșit pentru app-uri serverless.

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.