Transactions in Spring Data JPA

A transaction represents a unit of work that must be executed completely or not at all.

Spring Data JPA relies on Spring’s transaction management to ensure data consistency, integrity, and reliability.

Understanding transactions is critical because:

  • JPA entity state depends on transactions
  • Persistence context lifecycle depends on transactions
  • Most data bugs occur due to incorrect transactional boundaries

What is a Transaction?

A transaction is a sequence of operations that follows ACID properties:

  • Atomicity – All or nothing
  • Consistency – Data remains valid
  • Isolation – Concurrent transactions don’t interfere incorrectly
  • Durability – Committed data is permanent

In JPA, SQL execution and entity synchronization happen within a transaction.


Why Transactions Are Important

Without transactions:

  • Partial updates may occur
  • Data becomes inconsistent
  • Concurrent users overwrite data
  • Entity changes may not be saved

In enterprise and banking systems, transactions are mandatory.

Rule:
Any operation that modifies data must be transactional.


Where Transactions Belong

Correct Layer

Service layer

Incorrect Layers

❌ Controller
❌ Repository (business transactions)


Typical Flow

Controller
↓
@Service (@Transactional)
↓
Repository
↓
Database

Best Practice:
Keep transaction boundaries at the service layer.


@Transactional Annotation

Spring manages transactions using @Transactional.

Basic Usage

@Transactional
public void transferMoney(Long from, Long to, BigDecimal amount) {
    // business logic
}

Spring:

  • Opens transaction before method execution
  • Commits if method succeeds
  • Rolls back if method fails

Transaction Commit & Flush

  • Flush → Synchronizes persistence context with DB
  • Commit → Makes changes permanent

Hibernate:

  • Automatically flushes before commit
  • May flush before queries
repository.save(entity); // not immediately written to DB

Actual SQL execution happens:

  • At flush
  • Or at transaction commit

Rollback Rules

Default Behavior

Spring rolls back only on unchecked exceptions:

  • RuntimeException
  • Error

❌ Does NOT rollback on checked exceptions by default.


Custom Rollback Rules


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

Use when:

  • Checked exceptions represent business failure

Read-Only Transactions

@Transactional(readOnly = true)
public List<Customer> getCustomers() {
}

Benefits:

  • Optimized performance
  • Prevents accidental updates
  • Clear intent

Use read-only for query-only methods.


Transaction Propagation

Propagation defines how transactions behave when one transactional method calls another.


REQUIRED (Default)

@Transactional
  • Uses existing transaction
  • Creates new one if none exists

✔ Most common ✔ Safe default


REQUIRES_NEW

@Transactional(propagation = Propagation.REQUIRES_NEW)
  • Suspends existing transaction
  • Starts a new one

Use cases:

  • Audit logging
  • Notifications
  • Independent operations

SUPPORTS

  • Joins transaction if present
  • Runs non-transactional otherwise

NOT_SUPPORTED

  • Suspends existing transaction
  • Runs without transaction

Used rarely.


Transaction Isolation Levels (High-Level)

Isolation controls how concurrent transactions see data.

Common levels:

  • READ_COMMITTED (default)
  • REPEATABLE_READ
  • SERIALIZABLE

In most systems:

  • Default isolation is sufficient
  • Higher isolation = lower concurrency

Transactions & Entity Lifecycle (Connection)

  • Entities are managed only inside a transaction
  • After transaction ends → entities become detached
  • Lazy loading works only within transaction

This explains:

  • LazyInitializationException
  • Missing updates
  • Detached entity behavior

Common Transaction Mistakes

  • ❌ Placing @Transactional on controller
  • ❌ Forgetting transactions for write operations
  • ❌ Long-running transactions
  • ❌ Using REQUIRES_NEW blindly
  • ❌ Assuming save() commits immediately

Summary

  • @Transactional manages commit & rollback

  • Rollback happens on RuntimeException by default

  • Service layer owns transactions

  • Entities are managed within transactions

  • REQUIRES_NEW creates independent transaction

  • readOnly improves performance


Table of contents


This site uses Just the Docs, a documentation theme for Jekyll.