Backend Development 6 min read

Isolating Transactions in Spring Scheduled Tasks to Prevent Whole‑Loop Rollback

The article explains how to process a batch of overdue unpaid orders in a Spring scheduled task by wrapping each order's business logic in a separate REQUIRES_NEW transaction, catching exceptions, and manually rolling back only the failing transaction so that other orders remain unaffected.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Isolating Transactions in Spring Scheduled Tasks to Prevent Whole‑Loop Rollback

When a scheduled task needs to handle multiple overdue unpaid orders, a naïve implementation loops through the orders and executes business logic such as inventory rollback, order status update, audit logging, and message pushing; if an exception occurs on any iteration, the entire loop rolls back, causing all previously successful orders to be undone.

The proposed solution is to isolate each order's processing in its own transaction. By moving the business logic to a service method annotated with @Transactional(propagation = Propagation.REQUIRES_NEW) and catching any exception inside that method, you can call TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() to roll back only the failing transaction while allowing the surrounding loop to continue.

Below is the timer component that fetches the list of orders and iterates over them:

package demo;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class OrderTimer {
    private static Logger logger = Logger.getLogger(OrderTimer.class);

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderMapper orderMapper;

    /**
     * Execute every minute to close unpaid orders.
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void closeOrders() {
        logger.info("--------开始每隔1分钟执行未付款订单的关闭的操作");
        // Get all overdue unpaid orders (example only)
        List
list = orderMapper.listCloseOrder();
        if (list == null || list.size() < 1) {
            return;
        }
        for (Order order : list) {
            orderService.closeOrder(order);
        }
    }
}

The service implementation contains the critical points:

package demo;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Service
public class OrderServiceImpl implements OrderService {
    private static Logger logger = Logger.getLogger(OrderServiceImpl.class);

    @Autowired
    private OrderMapper orderMapper;

    /**
     * The REQUIRES_NEW propagation ensures each order is processed in an independent transaction.
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW) // Focus point 1
    @Override
    public void closeOrder(Order order) {
        try {
            // Your business logic here: inventory rollback, order status change, audit log, etc.
        } catch (Exception e) {
            logger.info("网络异常:" + e.getMessage());
            // Manually mark the current transaction for rollback so that only this order fails.
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); // Focus point 2
        }
    }
}

With this arrangement, if the sixth order throws an exception, only that transaction is rolled back while the first five and the remaining orders commit successfully, achieving isolation without affecting the whole batch.

The article notes that a full working example would require actual database tables and DAO implementations, which are omitted for brevity; the core idea is to encapsulate each loop iteration in its own transaction and handle exceptions locally.

Javatransactionbackend developmentSpringScheduled TaskREQUIRES_NEW
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow 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.