Why @Transactional Might Fail in Spring and How to Fix It

This article explains common reasons why Spring's @Transactional annotation can become ineffective—such as self‑invocation, non‑public methods, multiple data sources, incorrect rollback settings, and unsupported database engines—and provides concrete code examples and solutions to ensure proper transaction management.

Programmer DD
Programmer DD
Programmer DD
Why @Transactional Might Fail in Spring and How to Fix It

1. Self‑invocation within the same class

When a method annotated with @Transactional is called from another method of the same class, Spring AOP cannot create a proxy, so the transaction is not applied.

public class A {
    public void methodA() {
        methodB();
        // other operations
    }

    @Transactional
    public void methodB() {
        // write to database
    }
}

Solution: Move the transactional method to a separate bean so that Spring can proxy it.

@Service
@AllArgsConstructor
public class A {
    private B b;
    public void methodA() {
        b.methodB();
        // other operations
    }
}

@Service
public class B {
    @Transactional
    public void methodB() {
        // write to database
    }
}

2. @Transactional on a non‑public method

Spring AOP only intercepts public methods. If the annotated method has private, protected, or package‑private visibility, the transaction will not be started.

public class TransactionalMistake {
    @Transactional
    private void method() {
        // write to database
    }
}

Fix: Change the method visibility to public.

3. Multiple data sources

When a single operation writes to two different data sources, the default transaction manager cannot span them, so the transaction will not roll back.

public class TransactionalMistake {
    @Transactional
    public void createOrder(Order order) {
        orderRepo1.save(order);
        orderRepo2.save(order);
    }
}

Use a JTA transaction manager to coordinate transactions across multiple databases.

4. Incorrect rollback exception configuration

By default Spring rolls back only for RuntimeException and Error. Checked exceptions do not trigger a rollback unless configured.

Define custom exceptions as subclasses of RuntimeException or specify rollbackFor on the annotation.

@Transactional(rollbackFor = XXXException.class)
public void method() throws XXXException {
    // ...
}

5. Database engine does not support transactions

If the underlying tables use a storage engine without transaction support (e.g., MyISAM), the transaction will never roll back.

Ensure the dialect is set to an engine that supports transactions, such as InnoDB for MySQL:

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

Check the created tables to confirm they use InnoDB.

Conclusion

These are the most common pitfalls that cause @Transactional to be ineffective. If you encounter other scenarios, feel free to share them so the article can be updated for future readers.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaaopdatabasespringtransactional
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

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.