package com.ruoyi.order.util.task; import com.ruoyi.order.mapper.TChargingOrderMapper; import com.ruoyi.order.service.TChargingOrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.web.context.WebServerInitializedEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * 大屏预聚合表 t_large_screen_site_stat 定时任务 * * 背景: /large-screen/* 接口原 SQL 在 MyCat 分表下按 site_id 过滤会广播扫描 * 50 张 t_charging_order 物理表且跨分片 join, 导致读超时。 * 本任务按"月/日/全局"切片把聚合结果写入预聚合表(全局表), 接口改为读该表: * 1. 每日 00:30 全量重建(按月切片逐片查询, 单次查询有界, 规避 MyCat 读超时) * 2. 每 10 分钟刷新当月/当日/全局行, 保证大屏当前月、当日数据近实时 * 3. 启动时检测表为空则异步全量回填, 避免发布后接口无数据 */ @Slf4j @Component public class LargeScreenStatJob implements ApplicationListener { private Integer port; @Resource private TChargingOrderService chargingOrderService; @Resource private TChargingOrderMapper chargingOrderMapper; @Override public void onApplicationEvent(WebServerInitializedEvent event) { port = event.getWebServer().getPort(); } // 每日 00:30 全量重建 @Scheduled(cron = "0 30 0 * * ?") public void fullRebuild() { if (!TaskUtil.isScheduledTaskPort(port)) { return; } try { chargingOrderService.rebuildLargeScreenStat(); } catch (Exception e) { log.error("大屏预聚合表全量重建失败", e); } } // 每 10 分钟刷新当月/当日/全局 @Scheduled(fixedRate = 1000 * 60 * 10) public void refresh() { if (!TaskUtil.isScheduledTaskPort(port)) { return; } try { chargingOrderService.refreshLargeScreenStat(); } catch (Exception e) { log.error("大屏预聚合表刷新失败", e); } } // 启动时表空则异步全量回填, 不阻塞启动 @EventListener(ApplicationReadyEvent.class) public void backfillIfEmpty() { if (!TaskUtil.isScheduledTaskPort(port)) { return; } try { Long count = chargingOrderMapper.statTableCount(); if (count != null && count > 0) { return; } log.info("大屏预聚合表为空, 启动异步全量回填"); Thread backfill = new Thread(() -> { try { chargingOrderService.rebuildLargeScreenStat(); } catch (Exception e) { log.error("大屏预聚合表启动回填失败", e); } }, "large-screen-stat-backfill"); backfill.setDaemon(true); backfill.start(); } catch (Exception e) { log.error("大屏预聚合表启动回填检查失败", e); } } }