Skip to main content

Transaction Management in Spring Boot

Transaction Management in Spring Boot: Complete Deep Dive

Transaction Management is an essential Spring Boot interview topic because practically every enterprise application performs database operations that must be executed as a complete, atomic unit of work.

Money transfers, order placements, inventory updates, and payroll processing all require strict transactional boundaries. Without transactions, partial updates during a system crash lead directly to fatal data corruption.


1. What is a Transaction?

Standard Definition

A Transaction is a logical unit of work consisting of one or more database operations. It strictly follows an All-or-Nothing rule: Either every operation succeeds completely, or every operation rolls back entirely.

The Bank Transfer Scenario

Suppose you are transferring ₹2000 from Account A to Account B.

UPDATE account SET balance = balance - 2000 WHERE id = 1; UPDATE account SET balance = balance + 2000 WHERE id = 2;
  • Success Case: Money is deducted from A and added to B. Correct.
  • Failure Case: The money is deducted from A, but the server crashes before the second query runs. Account A loses money, Account B gets nothing. The money vanishes.

Transactions solve this. If the second query fails, the database automatically rolls back the first query, restoring Account A's balance to its original state.


2. The ACID Properties (Interview Favorite)

Every transaction guarantees four fundamental properties:

  • A - Atomicity: All-or-Nothing. Both the debit and credit succeed, or neither happens.
  • C - Consistency: The database state remains valid before and after the transaction. No orphaned records or mathematical impossibilities are allowed.
  • I - Isolation: Multiple concurrent transactions do not interfere with each other. If User A and User B modify balances simultaneously, the database isolates their actions to prevent data corruption.
  • D - Durability: Once a transaction is successfully committed, the data is permanently written to disk. Even if a sudden power failure occurs a millisecond later, the data survives.

3. Spring's Declarative Solution: @Transactional

Before Spring, managing transactions required massive amounts of manual, repetitive JDBC boilerplate code:

Connection connection = dataSource.getConnection(); connection.setAutoCommit(false); try { // Execute Queries here connection.commit(); } catch (Exception e) { connection.rollback(); }

Spring removes this boilerplate via Declarative Transaction Management. You simply annotate your business method with @Transactional.

@Service public class BankService { @Transactional public void transferMoney() { withdrawMoney(); depositMoney(); } }

Internal Flow: Spring automatically begins the transaction, executes your business logic, and commits. If your code throws a RuntimeException, Spring intercepts it and executes a complete rollback.


4. Internal Working of @Transactional (Most Asked Question)

Interview Insight

Most developers know how to use @Transactional. Interviewers ask: How does it work internally?

Answer: @Transactional operates using the Spring AOP Proxy Pattern combined with a TransactionInterceptor.

When Spring detects the @Transactional annotation on a Service bean, it does not give the Controller a direct reference to your Service class. Instead, it generates a Proxy Object wrapper around your class.

Client Request | V [ AOP Proxy Object ] | [ TransactionInterceptor ] ---> Intercepts Method Call | [ PlatformTransactionManager ] ---> BEGIN TRANSACTION | V [ Actual Target Service Method Executes ] | V [ TransactionInterceptor ] ---> Intercepts Return/Exception | [ PlatformTransactionManager ] ---> COMMIT (if Success) / ROLLBACK (if Error)

PlatformTransactionManager

This is the core engine executing the database commands. Depending on your stack, Spring Boot auto-configures the correct implementation:

  • DataSourceTransactionManager (For standard JDBC)
  • JpaTransactionManager (For JPA/Hibernate operations)

5. Transaction Attributes

The @Transactional annotation allows deep customization via its attributes:

@Transactional( propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, readOnly = true, timeout = 10 )

1. Propagation (How transactions interact)

If Method A (which has a transaction) calls Method B (which also has a transaction), Propagation defines how Method B should behave.

Propagation Type Behavior
REQUIRED (Default) If a transaction already exists, join it. If not, create a new one.
REQUIRES_NEW Suspend the current transaction, create a brand new independent transaction, execute, commit, then resume the old transaction. (Often used for Audit Logging).
SUPPORTS If a transaction exists, join it. If not, execute normally without a transaction.
MANDATORY A transaction must exist. If none exists, throw an Exception.
NOT_SUPPORTED Execute non-transactionally. If a transaction exists, suspend it during execution.

2. Isolation (Handling Concurrency)

Isolation dictates how isolated your transaction is from other concurrent transactions, preventing data corruption anomalies like Dirty Reads, Non-Repeatable Reads, and Phantom Reads.

Isolation Level Prevents Dirty Read? Prevents Non-Repeatable Read? Prevents Phantom Read?
READ_UNCOMMITTED No No No
READ_COMMITTED (Most Common) Yes No No
REPEATABLE_READ (MySQL Default) Yes Yes No
SERIALIZABLE (Slowest) Yes Yes Yes

3. Rollback Behavior (rollbackFor)

The Checked Exception Trap

By default, Spring will ONLY rollback a transaction for an Unchecked Exception (RuntimeException or Error).

If your code throws a Checked Exception like IOException, Spring will NOT rollback the transaction!

To force a rollback for checked exceptions, you must explicitly declare it:

@Transactional(rollbackFor = Exception.class)

4. readOnly & timeout

  • readOnly = true: Used strictly for SELECT queries. This is an optimization hint. Hibernate disables its "dirty checking" mechanism, which reduces memory overhead and improves performance.
  • timeout = 10: Specifies that the transaction must complete within 10 seconds. If it exceeds this limit, a TransactionTimedOutException is thrown and a rollback occurs. Ideal for protecting against deadlocks.

6. The Self-Invocation Problem (Crucial Concept)

This is an advanced interview trap. Consider this code:

@Service public class UserService { public void methodA() { methodB(); // Calling an internal method } @Transactional public void methodB() { // Database logic here } }

Question: Will methodB() execute inside a transaction?

Answer: NO.

Because Spring relies on the AOP Proxy wrapper, the proxy is only triggered when an external class calls the method. When methodA() calls methodB() internally (using this.methodB()), the call completely bypasses the proxy object. The @Transactional annotation on methodB() is completely ignored.


7. Best Practices

  • Apply at the Service Layer: @Transactional belongs on the Service layer where business logic coordinates multiple repository calls. Do NOT put it on Controllers.
  • Keep Transactions Small: Never place long-running loops, File Uploads, or slow third-party API HTTP calls inside a transaction. This locks database tables and causes connection pool exhaustion.
  • Use Custom RuntimeExceptions: Throw dedicated unchecked exceptions (e.g., UserNotFoundException extends RuntimeException) to ensure automatic rollbacks without needing rollbackFor.

8. Interview Checklist Summary

Top Interview Q&A

Q1: What is @Transactional?
A: It is an annotation that allows Spring to manage database transactions declaratively, removing the need for manual connection commit/rollback boilerplate code.

Q2: How does it work internally?
A: Spring uses AOP Proxies. It wraps the target class in a proxy. When a method is called, a TransactionInterceptor catches the call, instructs the PlatformTransactionManager to begin a transaction, executes the method, and triggers a commit or rollback based on success or exception.

Q3: What is the default rollback behavior?
A: It rolls back exclusively for Unchecked Exceptions (RuntimeException and Error). It does not roll back for Checked Exceptions unless configured via rollbackFor.

Q4: What is the default propagation behavior?
A: Propagation.REQUIRED. If a transaction exists, it joins it. If none exists, it creates a new one.

[ Complete Internal Architecture Diagram ] Client Request ↓ Controller ↓ Service (@Transactional) ↓ Spring AOP Proxy ↓ TransactionInterceptor ↓ JpaTransactionManager ↓ EntityManager ↓ Hibernate ↓ JDBC Connection ↓ Database (Commit or Rollback)

Comments

Popular posts from this blog

How I Got Selected in MNC

Virtusa Sometimes success does not come from having the best coding skills or the perfect roadmap. Sometimes it comes from simply refusing to quit. This is the honest story of how I transitioned from a confused, rejected fresher to getting selected as an Associate Engineer at Virtusa. The Beginning: Confused About My Future After completing my graduation, I stared blankly at my career options. Like many freshers, I lacked a clear direction. Should I join a Java course? Should I prepare on my own? Should I just wait for campus placement opportunities? One day, I called my friend Chetan. He suggested I join Naresh i Technologies and start learning Java seriously. Still unsure of my path, I told him I needed time to think about it. A couple of days later, my phone buzzed with a WhatsApp message offering a job opportunity. They asked me to come for the next round of the recruitment process. Excitement completely took over. I packed my bags, traveled to th...

Spring Boot Introduction

Spring Boot Introduction: Architecture, Dependencies, and Embedded Servers Modern enterprise applications demand rapid development, frictionless deployment, and absolute minimal configuration. Before Spring Boot arrived, developers utilizing the Spring Framework wasted immense amounts of time configuring XML files, managing clashing dependencies, setting up clunky application servers, and stitching various Spring modules together manually. To eliminate these bottlenecks, Pivotal introduced Spring Boot . Built entirely on top of the traditional Spring Framework, Spring Boot is an "opinionated" framework. It aggressively simplifies application development by injecting auto-configuration, packaging starter dependencies, and embedding web servers directly into your application. This allows backend developers to focus entirely on building business logic rather than wrestling with infrastructure setup. What is Spring Boot? Spring Boot is a powerful extens...

Strings in C

C Programming: Working with Strings Unlike modern programming languages like Python or Java, C does not possess a dedicated "String" data type. Instead, C treats a string as a simple 1D array of characters. Real-life example: Think of a freight train. The train does not exist as one solid object; it consists of individual boxcars linked together. Similarly, a C string links individual characters side-by-side in memory. To let the computer know the train has ended, C attaches a special "caboose" called the Null Terminator ( \0 ). 1. Essential String Functions Handling strings manually requires complex loops. To save time, C provides a built-in library called <string.h> that contains powerful functions to manipulate text. strlen(): You use this to find the exact length of a string. The compiler counts the characters until it hits the \0 terminator. It does not count the terminator itself. strcpy(): You ...