Why MyBatis‑Plus’s saveBatch Triggers Unexpected Transaction Rollbacks and How to Fix It

The article explains why the error "Transaction rolled back because it has been marked as rollback‑only" occurs in a Java Spring service when using MyBatis‑Plus saveBatch, how hidden @Transactional annotations cause hidden nested transactions, and presents a practical workaround by replacing the batch operation with a custom mapper.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Why MyBatis‑Plus’s saveBatch Triggers Unexpected Transaction Rollbacks and How to Fix It

In a Java Spring project the author encountered the error message

Transaction rolled back because it has been marked as rollback-only

during testing of a feature. The message indicates that a transaction was marked for rollback, typically due to an inner transaction failure while the outer transaction still attempts to commit.

The root cause is often nested transactions: the inner service method throws an exception, is caught, and marks the current transaction as rollback‑only. When the outer service later tries to commit, the transaction manager detects the rollback flag and throws the above error.

The author provides a simplified example where a service method annotated with @Transactional calls another service method also annotated with @Transactional. If the inner call fails, the outer transaction ends up with a rollback‑only flag, leading to the observed exception.

While investigating, the author discovered that MyBatis‑Plus’s saveBatch method internally adds a @Transactional annotation. This hidden annotation effectively creates a nested transaction even though the developer did not intend to use one.

Because the hidden transaction propagates with the default propagation (REQUIRED), the inner transaction’s rollback flag propagates to the outer transaction, reproducing the error when duplicate keys are present. The outer try‑catch block swallows the exception, so the failure only becomes visible at commit time.

Two obvious fixes are not feasible: removing the @Transactional annotation from saveBatch (it is part of the library source) or changing its propagation to REQUIRES_NEW or NESTED (also not configurable).

The practical solution is to avoid using MyBatis‑Plus’s saveBatch in this scenario and implement a custom batch insert via a mapper, thereby controlling the transaction boundaries explicitly.

After replacing saveBatch with a manual batch insert, the author redeployed the service, confirmed that the error no longer occurs, and concluded that third‑party code can introduce hidden transaction behavior that requires careful review.

Key takeaways: always verify the transactional semantics of third‑party utilities, especially batch operations, and be prepared to replace them with custom implementations when they interfere with your transaction design.

@Override
@Transactional(rollbackFor = Exception.class)
public Boolean xxx(xxx dto) {
    list1 = ...;
    try {
        // batch save list1 to DB
    } catch (Exception e) {
        if (e instanceof DuplicateKeyException) {
            // filter duplicate keys and save filtered list1
        }
        // other handling
    }
    sendToMQ(xxx);
    list2 = ...;
    try {
        // batch save list2 to DB
    } catch (Exception e) {
        if (e instanceof DuplicateKeyException) {
            // filter duplicate keys and save filtered list2
        }
        // other handling
    }
    sendToMQ(xxx);
    return Boolean.TRUE;
}
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.

JavaBackend DevelopmentSpringTransaction ManagementrollbackMyBatis-Plus
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

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.