Do transaction automatically rollback on error?

I was reading the docs about transactions and it is not clear whether the transaction is rolled back when an error is thrown. Which is:
const db = drizzle(...)

await db.transaction(async (tx) => {
const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
if (account.balance < 100) {
await tx.rollback()
// Can I use throw MyCustomError(); here instead of tx.rollback()?
// Will it also rollback the transaction?
return
}

await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
const db = drizzle(...)

await db.transaction(async (tx) => {
const [account] = await tx.select({ balance: accounts.balance }).from(accounts).where(eq(users.name, 'Dan'));
if (account.balance < 100) {
await tx.rollback()
// Can I use throw MyCustomError(); here instead of tx.rollback()?
// Will it also rollback the transaction?
return
}

await tx.update(accounts).set({ balance: sql`${accounts.balance} - 100.00` }).where(eq(users.name, 'Dan'));
await tx.update(accounts).set({ balance: sql`${accounts.balance} + 100.00` }).where(eq(users.name, 'Andrew'));
});
3 Replies
Angelelz
Angelelz•10mo ago
Yes, throwning an error is the way drizzle uses to stop execution of your transaction call back And calling rollback accordingly
AstroBear
AstroBearOP•10mo ago
Thanks, I also tested it and throwing any kind of error makes the transaction rollback 🙂
virtuaboza
virtuaboza•9mo ago
I came here to ask the same question because it is not working in my case, but my case might be a special case. This is my code:
return db.transaction(async (tx) => {
const organization = (
await tx
.insert(schema.organizations)
.values({
howHeard: input.howHeard,
name: input.organizationName,
})
.returning({ id: schema.organizations.id })
)[0]!;

const library = (
await tx
.insert(schema.libraries)
.values({
defaultConcurrentLoanLimit: input.concurrentLoanLimit,
defaultExtensionLimit: input.extensionLimit,
defaultLoanPeriodDays: input.loanPeriodDays,
excludeHolidaysWeekends: input.excludeHolidaysWeekends,
name: input.libraryName,
organizationId: organization.id,
})
.returning({ id: schema.libraries.id })
)[0]!;

await tx.insert(schema.organizationUsers).values({
organizationId: organization.id,
role: "ADMIN",
userId: ctx.user.id,
});

return library;
});
return db.transaction(async (tx) => {
const organization = (
await tx
.insert(schema.organizations)
.values({
howHeard: input.howHeard,
name: input.organizationName,
})
.returning({ id: schema.organizations.id })
)[0]!;

const library = (
await tx
.insert(schema.libraries)
.values({
defaultConcurrentLoanLimit: input.concurrentLoanLimit,
defaultExtensionLimit: input.extensionLimit,
defaultLoanPeriodDays: input.loanPeriodDays,
excludeHolidaysWeekends: input.excludeHolidaysWeekends,
name: input.libraryName,
organizationId: organization.id,
})
.returning({ id: schema.libraries.id })
)[0]!;

await tx.insert(schema.organizationUsers).values({
organizationId: organization.id,
role: "ADMIN",
userId: ctx.user.id,
});

return library;
});
And this fails for me on the last insert due to https://discord.com/channels/1043890932593987624/1120919676457848946/1120919676457848946, but when I check my database, the new organization and library did get inserted.
Discord
Discord - A New Way to Chat with Friends & Communities
Discord is the easiest way to communicate over voice, video, and text. Chat, hang out, and stay close with your friends and communities.
Want results from more Discord servers?
Add your server