Skip to main content
The @transactional decorator automatically wraps methods in transactions, reducing boilerplate code.

Decorator Overview

Automatic Transactions

Automatically wraps method execution in transaction Commits on success, rollbacks on failure

Cleaner Code

No need to call transaction() Improved readability

Isolation Level

Configure transaction isolation level Concurrency control

Nested Transactions

Same-preset DB transaction No automatic savepoint

Basic Usage

Before: Manual Transactions

After: @transactional Decorator

Methods decorated with @transactional() automatically run within a transaction.

How It Works

Decorator Options

dbPreset Setting

Isolation Level Setting

Isolation Level Considerations: - Higher isolation levels reduce concurrency - SERIALIZABLE has significant performance impact - REPEATABLE READ is appropriate for most cases

Practical Examples

Example 1: Simple Transaction

Example 2: Automatic Rollback

Example 3: Complex Transaction (Company → Dept → Employee)

Example 4: Concurrency Control

Nested Transactions

Automatic Transaction Reuse

Same-preset nested @transactional calls participate in one DB transaction. The outermost same-preset call owns commit and rollback.
Benefits of Nested Transactions: - Improved code reusability - Freedom to combine methods - Automatic transaction boundary management

Error and Savepoint Semantics

A same-preset nested @transactional call participates in the outer DB transaction. It does not create a new database transaction or savepoint, and the outermost call owns commit and rollback.
This example catches an application-level error thrown after the DB statements succeeded. The outer transaction may continue and commit those writes. A PostgreSQL statement error, such as a constraint or SQL failure, aborts the current PostgreSQL transaction; catching it alone does not make that transaction usable again.
If a direct DB query may fail and the outer transaction must recover, run that query in a nested getPuri("w").transaction(...) savepoint. If the whole composition must remain atomic, let an application-level error propagate out of the outermost @transactional call to roll everything back.

Using with @api

Combining Decorators

Pros and Cons

Pros

Cleaner Code

No need for transaction() calls Removes boilerplate

Readability

Clear transaction boundaries Focus on business logic

Auto Management

Auto commit/rollback handling Prevents mistakes

Reusability

Easy method composition Nested transaction support

Cons

Constraints

Only usable at method level Partial transactions not possible

Debugging

Transaction boundaries are hidden May be harder to trace issues

Usage Guidelines

When to Use?

✅ Recommended:
  • Entire method is one transaction
  • Multiple DB operations require atomicity
  • Code reuse is important
  • API handler methods
❌ Not Recommended:
  • Partial transactions within method
  • Complex transaction control needed
  • Transaction boundaries need to be explicit

Pattern Comparison

Important Notes

Must Follow: 1. Method must be async function 2. Access DB with this.getPuri("r" or "w") 3. Propagate application-level errors with throw (auto rollback) 4. Same-preset nested calls participate in the same DB transaction, and the outermost call owns commit/rollback

Common Mistakes

Next Steps

Manual Transactions

Using transaction() directly

Best Practices

Transaction usage guide

UpsertBuilder

Saving data in transactions

Decorators

Understanding Sonamu decorators