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•13mo ago
Yes, throwning an error is the way drizzle uses to stop execution of your transaction call back And calling rollback accordingly
AstroBear
AstroBearOP•13mo ago
Thanks, I also tested it and throwing any kind of error makes the transaction rollback 🙂
virtuaboza
virtuaboza•12mo 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.

Did you find this page helpful?