// 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.