SoFunction
Updated on 2025-04-14

Spring transaction management how to handle deletion operations and transaction rollback

introduction

In actual development, transaction management is one of the core mechanisms to ensure data consistency. Especially when it comes to database deletion operations, how to correctly handle delete failures, concurrent conflicts and other scenarios is a challenge that every developer needs to face. This article will analyze the deletion operation and rollback mechanism in Spring transactions in detail through a practical case and provide an optimization solution.

1. Problem background

In a certain advertising traffic control system, we need to delete invalid media advertising space increase records. The core code is as follows:

@Service
@Transactional
public class FlowTransactionalUtil {
    @Autowired
    private OpmMediaFlowControlConfirmService confirmService;

    public void deleteMediaFlowOnline(List<OpmMediaFlowControlEntity> list, long flowId) {
        List<Long> mediaAdList = ()
                .map(OpmMediaFlowControlEntity::getMediaAdId)
                .collect(());

        List<Long> deleteList = ((OpmMediaFlowControlConfirmEntity::getFlowId, flowId))
                .stream()
                .filter(e -> !(()))
                .map(OpmMediaFlowControlConfirmEntity::getId)
                .collect(());

        if (!(deleteList)) {
            ((deleteList) ? 1 : 0);
        }
    }
}

Problem phenomenon:

When removeByIds() returns false (deletion failed or record not deleted), a CustomerException is thrown and the transaction is rolled back.

Log display:

: Transaction processing request exception

2. Problem analysis

2.1 Transaction rollback mechanism

Spring rolls back transactions by default when an uncaught RuntimeException or Error is encountered. If CustomerException is not a subclass of RuntimeException, @Transactional(rollbackFor = ) needs to be declared explicitly.

2.2 Reason for removingByIds to return false

reason Should I roll back Handling suggestions
The record does not exist no Log logs without throwing exceptions
Concurrent conflict (deleted) no Log logs without throwing exceptions
Database exception yes Throw exception and roll back

3. Optimization plan

3.1 Distinguish between business exceptions and technical exceptions

Optimize the deleteFlowConfirm method to avoid rollback triggering due to legal scenarios such as "record does not exist":

private void deleteFlowConfirm(long flowId, List&lt;OpmMediaFlowControlConfirmEntity&gt; controlConfirms) {
    List&lt;Long&gt; list = ()
            .filter(e -&gt; ().equals(flowId))
            .map(OpmMediaFlowControlConfirmEntity::getId)
            .collect(());

    if (!(list)) {
        boolean isSuccess = (list);
        if (!isSuccess) {
            // Check whether the records to be deleted really exist            long actualExistCount = (
                (OpmMediaFlowControlConfirmEntity::getId, list)
            );
            if (actualExistCount &gt; 0) {
                throw new CustomerException("Delete failed, please try again or contact the administrator");
            } else {
                ("Try to delete a record that does not exist: flowId={}, ids={}", flowId, list);
            }
        }
    }
}

3.2 Explicitly declare transaction rollback rules

@Transactional(rollbackFor = {, })
public class FlowService {
    // ...
}

3.3 Concurrent scenario optimization

Solution 1: Optimistic lock retry

@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 100))
public void deleteWithRetry(List<Long> ids) {
    ((ids));
}

Solution 2: Pessimistic lock query

List<OpmMediaFlowControlConfirmEntity> list = (
    (OpmMediaFlowControlConfirmEntity::getFlowId, flowId)
);

4. Complete optimization code

@Service
@Transactional(rollbackFor = )
public class FlowService {
    @Autowired
    private OpmMediaFlowControlConfirmService confirmService;

    public void deleteMediaFlowOnline(List&lt;OpmMediaFlowControlEntity&gt; list, long flowId) {
        List&lt;Long&gt; mediaAdList = ()
                .map(OpmMediaFlowControlEntity::getMediaAdId)
                .collect(());

        // Direct condition deletion (avoid query - delete race conditions)        boolean success = (flowId, mediaAdList);
        (success);
    }
}

// Transaction assertion tool classpublic class TransactionAssert {
    public static void assertSuccess(boolean condition) {
        if (!condition) {
            throw new CustomerException(SupResultCode.CODE_900000, "The operation failed, please try again");
        }
    }
}

5. Log and monitoring suggestions

Add logs in a key location:

try {
    (list, flowId);
} catch (CustomerException e) {
    ("Deletion failed - flowId: {}, mistake: {}", flowId, ());
    throw e;
}

6. Summary

  • Identify transaction rollback conditions: Ensure that the exception type triggers rollback correctly.
  • Distinguish between business exceptions and technical exceptions: Avoid accidentally triggering rollbacks due to legal scenarios (if the record does not exist).
  • Optimize concurrent operations: Use lock mechanisms or retry strategies to reduce conflicts.
  • Enhanced logging: facilitates quick location of problems.

Through the above optimization, the robustness and maintainability of the system can be significantly improved.

This is the article about Spring transaction management on how to deal with deletion operations and transaction rollback. For more related Spring transaction management content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!