8 Hidden Spring Transaction Pitfalls That Can Break Your Java Apps

This article reveals ten common Spring transaction pitfalls—including private methods, final modifiers, self‑invocation, missing @Service, wrong propagation, non‑transactional databases, swallowed or wrong exceptions, multi‑threaded calls, and nested transaction rollbacks—that can silently disable transaction management in Java backend projects.

Java Backend Technology
Java Backend Technology
Java Backend Technology
8 Hidden Spring Transaction Pitfalls That Can Break Your Java Apps

For Java developers, Spring's transaction management is familiar, but it contains many hidden pitfalls that can cause transactions to silently fail.

1. Incorrect access modifier

If a @Transactional method is declared private, Spring's proxy cannot intercept it, so the transaction is ignored.

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    private void add(UserModel userModel) {
        userMapper.insertUser(userModel);
    }
}

2. Method declared final

Final methods cannot be overridden by the proxy, preventing transaction activation.

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public final void add(UserModel userModel) {
        userMapper.insertUser(userModel);
    }
}

3. Self‑invocation

Calling another @Transactional method from within the same class uses the raw this reference, bypassing the proxy, so the inner method runs without a transaction.

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void add(UserModel userModel) {
        userMapper.insertUser(userModel);
        updateStatus(userModel);
    }

    @Transactional
    public void updateStatus(UserModel userModel) {
        // …
    }
}

4. Bean not managed by Spring

Without @Service (or another stereotype), the class is not a Spring bean and its methods are never proxied.

// @Service is missing
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Transactional
    public void add(UserModel userModel) {
        userMapper.insertUser(userModel);
    }
}

5. Wrong propagation setting

Using Propagation.NEVER disables transaction creation; only REQUIRED, REQUIRES_NEW and NESTED start a new transaction.

@Transactional(propagation = Propagation.NEVER)
public void add(UserModel userModel) {
    userMapper.insertUser(userModel);
}

6. Database engine without transaction support

Tables created with MyISAM (or similar) support only table locks and cannot participate in transactions.

7. Swallowing exceptions

Catching exceptions without rethrowing prevents Spring from detecting a failure, so the transaction is not rolled back.

@Transactional
public void add(UserModel userModel) {
    try {
        userMapper.insertUser(userModel);
    } catch (Exception e) {
        log.error(e.getMessage(), e);
        // no rethrow
    }
}

8. Throwing checked exceptions

Spring rolls back only on RuntimeException or Error by default; throwing a checked Exception will not trigger a rollback.

@Transactional
public void add(UserModel userModel) throws Exception {
    try {
        userMapper.insertUser(userModel);
    } catch (Exception e) {
        log.error(e.getMessage(), e);
        throw new Exception(e);
    }
}

9. Multi‑threaded calls

When a @Transactional method starts a new thread, the new thread obtains a different database connection, resulting in separate transactions.

@Transactional
public void add(UserModel userModel) throws Exception {
    userMapper.insertUser(userModel);
    new Thread(() -> roleService.doOtherThing()).start();
}

10. Nested transaction rolls back the outer work

Using Propagation.NESTED creates a savepoint, but if the outer transaction rolls back, the inner work is also undone.

@Transactional
public void add(UserModel userModel) throws Exception {
    userMapper.insertUser(userModel);
    roleService.doOtherThing(); // @Transactional(propagation = Propagation.NESTED)
}

Understanding these pitfalls helps avoid silent transaction failures in Spring‑based backend applications.

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.

JavatransactionaopspringSpringBootPitfalls
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.