乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 批处理概述与 Spring Batch 核心理念

    • Spring Batch 概述
    • Job-Instance-Execution 三层生命周期
    • 三层架构
    • Chunk 处理模型
    • Tasklet 处理模型
  • 第2章 Job与作业配置

    • Job 详解
    • Job 配置
    • JobLauncher 详解
    • JobParameters 详解
    • JobRepository 详解
  • 第3章 Step与执行模型

    • Step 详解
    • Step 配置
    • ExecutionContext 详解
    • ItemStream 与状态管理
    • StepScope 与 JobScope
  • 第4章 ItemReader数据读取

    • ItemReader 详解
    • FlatFileItemReader 详解
    • JdbcItemReader 详解
    • MultiResourceItemReader 详解
  • 第5章 ItemProcessor 数据处理

    • ItemProcessor 详解
  • 第6章 ItemWriter 数据写出

    • ItemWriter 详解
    • FlatFileItemWriter 详解
    • CompositeItemWriter 详解
    • JdbcBatchItemWriter 详解
  • 第7章 Chunk 处理与事务边界

    • Chunk 处理模型详解
    • 事务边界
  • 第8章 作业参数与启动

    • 命令行与 Web 启动
  • 第9章 监听器与拦截器

    • 监听器详解
  • 第10章 重启重试与跳过策略

    • 重启与重试
    • 跳过策略
  • 第11章 作业流与条件决策

    • 作业流与条件决策
  • 第12章 分区与并行处理

    • 分区详解
    • 并行 Step 与 Split
  • 第13章 与 Spring Boot 集成实践

    • Spring Boot 集成
  • 第15章 运维与监控

    • 大作业设计模式
    • 运维与监控

运维与监控

本章定位:掌握 Spring Batch 的运维工具——元数据表查询、JobOperator 管理 API 和常见故障处理。

定义与作用

Spring Batch 将所有作业执行记录持久化在元数据表中。通过这些表和 JobOperator / JobExplorer API,可以实现作业状态查询、停止、重启和审计。

飞翔科技运维黄俪的日常:

"凌晨 2 点定时 Job 失败了,我不用翻日志。直接查 BATCH_JOB_EXECUTION 表看 ExitMessage,定位到是第 3 个 Step 数据库连接超时。重启后从断点继续。"

核心原理

元数据表关系

完整示例

常用运维 SQL

-- 查看最近 5 次失败的 Job
SELECT je.JOB_EXECUTION_ID, ji.JOB_NAME,
       je.START_TIME, je.END_TIME, je.EXIT_CODE, je.EXIT_MESSAGE
FROM BATCH_JOB_EXECUTION je
JOIN BATCH_JOB_INSTANCE ji ON ji.JOB_INSTANCE_ID = je.JOB_INSTANCE_ID
WHERE je.STATUS = 'FAILED'
ORDER BY je.START_TIME DESC
LIMIT 5;

-- 查看某次执行中各 Step 的读写统计
SELECT STEP_NAME, STATUS, READ_COUNT, WRITE_COUNT,
       SKIP_COUNT, COMMIT_COUNT, ROLLBACK_COUNT
FROM BATCH_STEP_EXECUTION
WHERE JOB_EXECUTION_ID = 12345
ORDER BY STEP_EXECUTION_ID;

-- 统计每日 Job 执行次数
SELECT DATE(START_TIME) as batch_date, JOB_NAME, COUNT(*) as runs,
       SUM(CASE WHEN STATUS='COMPLETED' THEN 1 ELSE 0 END) as success,
       SUM(CASE WHEN STATUS='FAILED' THEN 1 ELSE 0 END) as failed
FROM BATCH_JOB_EXECUTION je
JOIN BATCH_JOB_INSTANCE ji ON ji.JOB_INSTANCE_ID = je.JOB_INSTANCE_ID
WHERE START_TIME >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY DATE(START_TIME), JOB_NAME;

JobOperator API 运维操作

@RestController
@RequestMapping("/ops/batch")
public class BatchOpsController {

    private final JobOperator jobOperator;
    private final JobExplorer jobExplorer;

    public BatchOpsController(JobOperator jobOperator, JobExplorer jobExplorer) {
        this.jobOperator = jobOperator;
        this.jobExplorer = jobExplorer;
    }

    // 查询所有正在运行的 Job
    @GetMapping("/running")
    public Set<Long> getRunningJobs() {
        return jobOperator.getRunningExecutions("anyJob");
    }

    // 停止作业
    @PostMapping("/stop/{executionId}")
    public String stop(@PathVariable long executionId) {
        jobOperator.stop(executionId);
        return "Stop signal sent to execution #" + executionId;
    }

    // 重启失败作业
    @PostMapping("/restart/{executionId}")
    public Long restart(@PathVariable long executionId) {
        return jobOperator.restart(executionId);
    }

    // 作业摘要
    @GetMapping("/summary/{executionId}")
    public String getSummary(@PathVariable long executionId) {
        return jobOperator.getSummary(executionId);
    }
}

应用健康检查

@Component
public class BatchHealthIndicator implements HealthIndicator {

    private final JobExplorer jobExplorer;

    public BatchHealthIndicator(JobExplorer jobExplorer) {
        this.jobExplorer = jobExplorer;
    }

    @Override
    public Health health() {
        // 检查最近 1 小时是否有失败的 Job
        LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);

        List<JobInstance> failedJobs = jobExplorer.findJobInstancesByJobName(
                "orderProcessingJob", 0, 100).stream()
                .flatMap(ji -> jobExplorer.getJobExecutions(ji).stream())
                .filter(job -> job.getStatus() == BatchStatus.FAILED
                        && job.getEndTime() != null
                        && job.getEndTime().isAfter(Date.from(
                            oneHourAgo.atZone(ZoneId.systemDefault()).toInstant())))
                .map(JobExecution::getJobInstance)
                .toList();

        return failedJobs.isEmpty()
            ? Health.up().withDetail("recentFailures", 0).build()
            : Health.down().withDetail("recentFailures", failedJobs.size()).build();
    }
}

易错场景与避坑

反例一:不清理历史数据导致元数据表膨胀

-- 100 个 Job × 每天 24 次 × 365 天 × 5 年 = 4,380,000 行
-- BATCH_STEP_EXECUTION 表可能到千万行 → 查询缓慢

正确做法:定期清理(保留 30-90 天):

DELETE FROM BATCH_STEP_EXECUTION_CONTEXT
WHERE STEP_EXECUTION_ID IN (
    SELECT STEP_EXECUTION_ID FROM BATCH_STEP_EXECUTION
    WHERE JOB_EXECUTION_ID IN (
        SELECT JOB_EXECUTION_ID FROM BATCH_JOB_EXECUTION
        WHERE END_TIME < DATE_SUB(NOW(), INTERVAL 90 DAY)
    )
);

反例二:Web 应用中忘记关掉自动执行

// ❌ 应用启动时自动跑批处理 → 启动极慢、可能数据冲突
// spring.batch.job.enabled 默认 true

面试高频考点

Q1:如何实现 Job 执行失败后的告警?

两种方式:①监听器方式——JobExecutionListener.afterJob() 中检查 STATUS=FAILED,发送邮件/钉钉/企微。②轮询方式——定时查询 BATCH_JOB_EXECUTION 表,查找近期失败记录并告警。

Q2:stop() 和 abandon() 的区别?

stop() 发送停止信号(设置 STOPPING 状态),Job 在当前 Chunk 完成后优雅停止,状态变为 STOPPED,可以重启。abandon() 标记为 ABANDONED,放弃该次执行,不可重启。


全文完 | Spring Batch 独立教程 14 章

上一页
大作业设计模式