@Transactional Explained — What It Really Does (and What It Doesn’t)

@Transactional is one of the most used — and most misunderstood — annotations in the Java ecosystem.

Many developers know how to use it. Fewer truly understand what happens under the hood, where it breaks, and how it affects architecture.

Let’s fix that.


What Is @Transactional?

@Transactional defines a transaction boundary.

It tells the framework (Spring / Jakarta EE):

“All operations inside this method must execute as a single atomic unit.”

Meaning:

  • all succeed → commit
  • any failure → rollback

It applies only within a single transactional resource (usually one database).


How @Transactional Works (Important!)

@Transactional is implemented using AOP (proxies).

That implies:

  • It only works when the method is called from outside the class
  • Internal method calls (self-invocation) bypass the transaction
  • Final methods and private methods are not proxied

❌ This does not work as expected:

@Transactional
public void methodA() {
    methodB(); // no transaction here
}

@Transactional
public void methodB() { }        

This is one of the most common bugs in Spring applications.


Rollback Rules (Very Important)

By default, Spring rolls back only on:

  • RuntimeException
  • Error

Checked exceptions do NOT trigger rollback unless specified.

@Transactional(rollbackFor = Exception.class)
public void process() throws Exception { }        

If you don’t know this rule, you’ve probably shipped bugs to production.


Propagation — How Transactions Interact

Propagation defines how a transactional method behaves when another transaction already exists.

Common modes:

- REQUIRED (default)

Join existing transaction or create one.

- REQUIRES_NEW

Always start a new transaction (suspends the existing one).

- MANDATORY

Fails if no transaction exists.

- NOT_SUPPORTED

Runs without a transaction.

Example:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void auditLog() { }        

Critical for logging, retries, and compensations.


Isolation — Controlling Data Visibility

Isolation defines how concurrent transactions see each other’s data:

  • READ_UNCOMMITTED
  • READ_COMMITTED
  • REPEATABLE_READ
  • SERIALIZABLE

Higher isolation = more consistency + less concurrency.

@Transactional(isolation = Isolation.READ_COMMITTED)        

Most systems rely on the database default — but knowing this matters for race conditions.


Read-Only Transactions

@Transactional(readOnly = true)
public List<Order> findOrders() { }        

Benefits:

  • hints to the persistence provider
  • avoids unnecessary flushes
  • improves performance
  • documents intent

It does not prevent writes at the database level.


What @Transactional Does NOT Do

This is where many architects get burned:

❌ It does NOT span multiple microservices

❌ It does NOT guarantee distributed consistency

❌ It does NOT replace Saga or CQRS

❌ It does NOT protect external API calls

❌ It does NOT work across threads

❌ It does NOT work with async execution

@Transactional is local, not global.


@Transactional in Modern Architectures

In modern systems:

  • Use @Transactional on command/write paths
  • Keep transactions short
  • Avoid network calls inside transactions
  • Combine with:
  • Let transactions protect business invariants, not workflows


Best Practices (Hard-Learned)

  • Keep transactional boundaries small
  • Avoid lazy loading outside transactions
  • Never assume rollback without checking exception types
  • Don’t mix reads and writes unnecessarily
  • Don’t use transactions as workflow control
  • Prefer eventual consistency across services


Final Thought

@Transactional is one of the most powerful tools in Java — but also one of the easiest to misuse.

Used correctly, it protects data integrity. Used blindly, it creates hidden bugs, deadlocks, and scalability limits.

Understanding it deeply is a career-level skill, not a beginner detail.

#Java #Spring #Transactional #SoftwareArchitecture #BackendDevelopment #Microservices #CQRS #CleanCode #Engineering

Precisely explained!

Like
Reply

Nice recap, it would be great one about sagas and trx

Like
Reply

To view or add a comment, sign in

More articles by Henrique Eichler

Others also viewed

Explore content categories