Manual transaction commit, rollback
typescript - Using Prisma and transactions? - Stack Overflow
Are `prisma.$transactions` wrapped inside `BEGIN` and `COMMIT` for postgres?
API for interactive transactions with dependencies between write-operations
I realized, that for your specific usecase you could also increment your incrementalReportNumber with an atomic number operation
This avoids the need for a stricter transaction isolation level, because you only run update queries and avoid all read queries:
const report = await prisma.$transaction(async (prisma) => {
const school = await prisma.school.update({
where: { id: schoolId },
data: {
incrementalReportNumber: {
// increment the report number here
increment: 1,
},
},
});
const newReport = await prisma.report.create({
data: {
publicId: school.incrementalReportNumber,
schoolId: school.id,
name: reportName,
},
});
return newReport;
});
I think the issue here is with the transaction isolation level used by Prisma when running the query.
The default transaction isolation level in Postgres is "read committed", this is what Prisma uses and it does not prevent non-repeatable reads.
Non-Repeatable Reads
If you're not sure what non-repeatable reads are, I am adding a good explanation taken from here
"A non-repeatable read is one in which data read twice inside the same transaction cannot be guaranteed to contain the same value. Depending on the isolation level, another transaction could have nipped in and updated the value between the two reads.
Non-repeatable reads occur because at lower isolation levels reading data only locks the data for the duration of the read, rather than for the duration of the transaction"
In your case, the following race condition might be happening due to non-repeatable reads.
- Transaction B: Read school data with report number x and increment to x + 1.
- Transaction A: Read school data with report number x and increment to x + 1.
- Transaction B: Commit report number x + 1 to database.
- Transaction A: Attempt to create report with x+1 report number and fail.
Unfortunately, Prisma does not currently support changing the transaction isolation level. So, you might need to come to some other workaround for this issue (possibly even writing raw SQL code).
We have a feature request for exactly this and I would really urge you to comment your problem over there. That way it would help us track demand for this feature and incentivize adding it quickly.