Backend Development 13 min read

Common Scenarios Where Spring @Transactional Fails and How to Avoid Them

This article explains the fundamentals of database transactions, introduces Spring's @Transactional annotation, and enumerates nine typical situations—such as incorrect method visibility, final methods, self‑invocation, unmanaged beans, multithreading, wrong propagation, swallowed exceptions, unsupported exception types, and non‑transactional storage engines—where transactions may not work as expected, offering guidance to prevent these pitfalls.

政采云技术
政采云技术
政采云技术
Common Scenarios Where Spring @Transactional Fails and How to Avoid Them

Database transactions are a logical unit of work that must either complete fully or not at all, adhering to the ACID properties (Atomicity, Consistency, Isolation, Durability).

In Spring projects, transaction management is usually achieved with the @Transactional annotation, which creates a proxy database connection that is shared across all operations within the transaction.

Typical usage in a service layer may involve multiple DAO calls, for example:

Controller layer:
  UserService:addUser();
Service layer (UserService):
  addUser(): insertUser() + insertLog()
Dao layer:
  UserDao: insertUser();
  LogDao: insertDao();

Spring provides several attributes for @Transactional , such as isolation level, timeout, read‑only flag, rollback rules, and propagation behavior.

Isolation Levels

Isolation Level

Description

ISOLATION_DEFAULT

Uses the database's default isolation (MySQL: REPEATABLE READ).

ISOLATION_READ_UNCOMMITTED

Allows dirty reads; high concurrency but risks data inconsistency.

ISOLATION_READ_COMMITTED

Prevents dirty reads; a transaction sees only committed data.

ISOLATION_REPEATABLE_READ

Prevents non‑repeatable reads; the default for MySQL InnoDB.

ISOLATION_SERIALIZABLE

Highest isolation; forces sequential execution of all SQL statements.

Other attributes include:

Timeout (e.g., @Transactional(timeout = 30) ) defines how long a transaction may run before being rolled back.

Read‑only (e.g., @Transactional(readOnly = true) ) marks a transaction as read‑only.

Rollback rules (e.g., @Transactional(rollbackFor = Exception.class) ) specify which exceptions trigger a rollback.

Propagation (e.g., @Transactional(propagation = Propagation.REQUIRED) ) defines how transactions interact; see the table below.

Propagation Types

Propagation

Description

PROPAGATION_REQUIRED

Join existing transaction or create a new one if none exists (default).

PROPAGATION_SUPPORTS

Execute within a transaction if present; otherwise run non‑transactionally.

PROPAGATION_MANDATORY

Must run within an existing transaction; throws exception otherwise.

PROPAGATION_REQUIRES_NEW

Always creates a new transaction, suspending any existing one.

PROPAGATION_NOT_SUPPORTED

Suspends any existing transaction and runs non‑transactionally.

PROPAGATION_NEVER

Throws an exception if a transaction exists; otherwise runs non‑transactionally.

PROPAGATION_NESTED

Executes within a nested transaction if a current transaction exists; otherwise behaves like REQUIRED.

Common Situations Where @Transactional Does Not Take Effect

Method Visibility : Only public methods are proxied. Example of a private method annotated with @Transactional will not start a transaction.

Final Methods : final methods cannot be overridden by CGLIB proxies, so transaction logic is not applied.

Self‑Invocation : Calling a transactional method from within the same class bypasses the proxy, preventing transaction creation.

Bean Not Managed by Spring : Classes not annotated with @Service , @Component , etc., are not registered as beans, so AOP cannot apply.

Multithreading : Transactions are bound to a single database connection; spawning new threads obtains separate connections, breaking the transaction.

Incorrect Propagation Settings : Using Propagation.NEVER on a method called within an existing transaction causes an exception.

Swallowing Exceptions : If a transactional method catches exceptions without rethrowing, Spring assumes normal execution and will not roll back.

Unhandled Exception Types : By default, only RuntimeException triggers rollback. Checked exceptions must be specified via rollbackFor .

Non‑Transactional Storage Engine : Using a database engine that does not support transactions (e.g., MySQL MyISAM) renders transaction annotations ineffective.

Conclusion

The article outlines the principles of Spring's @Transactional annotation and lists the most common reasons why a transaction may not be applied, such as self‑invocation, swallowed exceptions, and mismatched exception types. Understanding these pitfalls helps developers use @Transactional correctly and avoid data inconsistencies.

BackendJavaTransactionAOPSpringTransactional
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.