使用quartz定时任务实现支付单自动关单功能,并引入多线程+分段解决扫表延迟的问题

在使用Quartz定时任务实现支付单的自动关单功能时,可以通过结合多线程和分段处理来优化系统的性能,尤其是在订单数据量较大的情况下,避免扫表延迟问题。
设计思路

  1. Quartz定时任务:
    定期触发任务扫描未支付的订单,并关闭那些超时未支付的订单。
  2. 多线程+分段处理:
    对订单数据进行分段处理,每个线程负责处理一部分数据,避免全量扫表带来的延迟问题。
  3. 任务拆分:
    根据订单的总数量,将其划分为若干批次(分段),使用线程池中的多个线程并行处理。
    实现步骤
  4. 创建订单关闭服务
    编写服务类,负责从数据库中查找超时未支付的订单并进行关闭操作。
@Service
public class OrderCloseService {

    // 模拟订单关闭逻辑
    public void closeOrder(Long orderId) {
        // 实际业务逻辑:如调用数据库更新订单状态为已关闭
        System.out.println("关闭订单:" + orderId);
    }

    // 查询超时未支付订单
    public List<Long> getTimeoutOrders(int offset, int limit) {
        // 模拟分页查询数据库中的超时未支付订单
        // offset是偏移量,limit是每页大小
        List<Long> orderIds = new ArrayList<>();
        for (long i = offset; i < offset + limit; i++) {
            orderIds.add(i);  // 模拟获取订单ID
        }
        return orderIds;
    }
}
  1. 配置Quartz定时任务
    Quartz的定时任务类,用来定期触发订单关闭任务。
@Component
public class OrderCloseJob implements Job {

    @Autowired
    private OrderCloseService orderCloseService;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    private static final int PAGE_SIZE = 100; // 每个批次处理的订单数量

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 获取需要关闭的订单总数
        int totalOrders = getTotalOrderCount(); // 假设有方法能获取订单总数
        int totalPages = (totalOrders + PAGE_SIZE - 1) / PAGE_SIZE;

        // 分页获取并关闭订单
        for (int page = 0; page < totalPages; page++) {
            int offset = page * PAGE_SIZE;
            taskExecutor.execute(() -> {
                // 多线程执行每页的订单关闭操作
                List<Long> orders = orderCloseService.getTimeoutOrders(offset, PAGE_SIZE);
                for (Long orderId : orders) {
                    orderCloseService.closeOrder(orderId);
                }
            });
        }
    }

    // 模拟获取超时订单总数的方法
    private int getTotalOrderCount() {
        // 实际上应查询数据库返回超时未支付订单的总数量
        return 1000; // 假设有1000个订单
    }
}
  1. 配置线程池
    通过自定义线程池来实现多线程处理,使用Spring Boot中的ThreadPoolTaskExecutor。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
public class ThreadPoolConfig {

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);  // 核心线程数
        executor.setMaxPoolSize(20);   // 最大线程数
        executor.setQueueCapacity(500);// 队列容量
        executor.setThreadNamePrefix("OrderCloseThread-");
        executor.initialize();
        return executor;
    }
}
  1. Quartz定时任务的配置
    通过QuartzConfig来配置任务的触发频率及初始化。
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {

    @Bean
    public JobDetail orderCloseJobDetail() {
        return JobBuilder.newJob(OrderCloseJob.class)
                .withIdentity("orderCloseJob")
                .storeDurably()
                .build();
    }

    @Bean
    public Trigger orderCloseTrigger() {
        // 每5分钟执行一次
        return TriggerBuilder.newTrigger()
                .forJob(orderCloseJobDetail())
                .withIdentity("orderCloseTrigger")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInMinutes(5)
                        .repeatForever())
                .build();
    }
}

核心点解释

  1. 定时任务(Quartz):OrderCloseJob类负责触发定时任务,每次执行时,它会获取超时未支付的订单,并通过线程池并行处理。
  2. 分页处理:通过offset和limit对订单进行分页处理,每个线程负责处理一部分订单,避免一次性加载过多数据带来的内存和性能问题。
  3. 多线程处理:ThreadPoolTaskExecutor被用来并行执行关闭订单的操作。它可以通过设置核心线程数、最大线程数和队列容量来优化任务执行的效率。
  4. 解决扫表延迟问题:使用分页和多线程,减轻了数据库的压力,同时提高了订单关闭的处理速度。即便订单量非常大,这种方案也能快速响应,不会造成长时间的表扫描。
    性能优化
    ● 分段处理:通过分批次的方式,每个线程只处理一部分订单,避免全量扫表的性能瓶颈。
    ● 线程池控制并发:使用线程池可以控制并发的线程数,防止系统因为并发过高导致崩溃或性能下降。
    这种设计在处理大量数据时能够显著提升系统性能,并且可以适应实际业务场景中订单数据的增长。

猜你喜欢

转载自blog.csdn.net/Fireworkit/article/details/142997805