王旭阳个人博客

WXY

Spring Batch on 达梦(Dameng):一篇全面的 ‘踩坑’ 与 ‘填坑’ 实战指南

2025-07-15

引言

Spring Batch 作为 Java 生态中处理批量任务的王者级框架,以其强大的功能、稳定性和可扩展性而备受青睐。然而,当我们的项目选择了国产的达梦(Dameng)数据库时,一场关于“兼容性”的挑战便拉开了序幕。Spring Batch 并未对达梦数据库提供开箱即用的支持,这导致在集成过程中会遇到一系列令人困惑的启动错误。

本文旨在记录并解决这一系列“踩坑”过程,最终提供一套经过验证的、能在生产环境中稳定运行的“填坑”方案,帮助您在达梦数据库上平稳地驾驭 Spring Batch。

环境说明:

  • Spring Boot Version: 2.7.x

  • Database: 达梦数据库 8 (DM8)

一、 踩坑之旅:还原错误现场

当我们简单地将 spring-boot-starter-batch 引入一个配置了达梦数据源的 Spring Boot 项目后,通常会按顺序遇到以下三个经典的启动失败错误。

错误一:JobBuilderFactory 找不到

Parameter 0 of constructor in ... required a bean of type 'org.springframework.batch.core.configuration.annotation.JobBuilderFactory' that could not be found.
  • 踩坑分析: 这是最基础的配置错误。错误日志告诉我们,Spring 的依赖注入容器找不到 JobBuilderFactory 这个核心 Bean。

  • 填坑方案: 在任何一个 @Configuration 类(通常是主启动类)上添加 @EnableBatchProcessing 注解。这个注解是激活 Spring Batch 自动配置的开关,一旦加上,JobBuilderFactoryStepBuilderFactory 等核心组件就会被自动注册到容器中。

错误二:Unable to detect database type

java.lang.IllegalStateException: Unable to detect database type
  • 踩坑分析: 解决了第一个问题后,Spring Batch 开始尝试初始化。它需要知道你连接的是什么数据库,以便使用正确的SQL方言和Schema脚本。但由于达梦数据库的JDBC驱动信息不被 Spring Boot 默认识别,导致自动检测失败。

填坑方案: 我们需要手动告诉 Spring Batch 数据库的类型。由于达梦在语法上与Oracle高度兼容,我们可以在 application.yml 中明确指定平台为 oracle

spring:
  batch:
    jdbc:
      platform: oracle

错误三:No schema scripts found at location ...schema-oracle.sql

java.lang.IllegalStateException: No schema scripts found at location 'classpath:org/springframework/batch/core/schema-oracle.sql'
  • 踩坑分析: 这个错误是上一步解决方案的直接“副作用”。我们告诉了 Spring Batch 把它当作 Oracle,于是它就去寻找 schema-oracle.sql 脚本来自动创建元数据表,但因为各种原因(如依赖、类加载问题)它没能成功。更重要的是,在生产环境中让应用自动修改数据库结构是一种非常危险的行为。

填坑方案: 我们应该完全接管数据库表的创建过程。在 application.yml 中设置初始化策略为 NEVER

spring:
  batch:
    jdbc:
      initialize-schema: NEVER
      platform: oracle # platform 最好还是保留,因为它可能影响运行时SQL的生成

至此,我们已经通过配置解决了所有启动时的问题。但应用能启动不代表能正常工作,我们还需要为 Spring Batch 准备好它所依赖的数据库表。

二、 终极解决方案:三步走实现完美兼容

在排除了所有启动错误后,我们来整理一下最终的、干净的配置方案。

第一步:环境与依赖配置

添加达梦JDBC驱动: 确保 pom.xml 中有正确的驱动依赖。

<dependency>
    <groupId>com.dameng</groupId>
    <artifactId>DmJdbcDriver18</artifactId>
    <version>8.1.1.49</version>
</dependency>

完成 application.yml 配置:

spring:
  datasource:
    url: jdbc:dm://localhost:5236/YOUR_DB?schema=IVS
    username: your_username
    password: your_password
    driver-class-name: dm.jdbc.driver.DmDriver
  batch:
    jdbc:
      # 1. 禁止自动初始化,我们手动管理Schema
      initialize-schema: NEVER
      # 2. 告诉Batch运行时SQL方言参考Oracle
      platform: oracle

第二步:手动创建元数据表

这是最关键的一步。我们需要为达梦数据库准备一份建表脚本。

2025-07-15-btfeggwr.webp

  1. 获取模板: 从 Spring Batch 的核心jar包 (spring-batch-core-*.jar) 的 org/springframework/batch/core/ 路径下,找到 schema-oracle.sql 文件。

  2. 修改脚本: 将其内容复制出来,并进行以下两处微调,使其更适合达梦数据库。

    • 将所有 VARCHAR2(n char) 修改为 VARCHAR(n)

    • 将所有序列的 START WITH 0 修改为 START WITH 1(最佳实践)。

  3. 指定模式: 为所有表名和序列名前面加上模式前缀,例如 IVS.

  4. 在数据库执行sql 生成初始化表

2025-07-15-fgxghykp.webp

第三步:(推荐) 自定义配置,确保运行时兼容

为了确保 Spring Batch 在运行时(如分页查询)也能生成正确的SQL,推荐创建一个自定义的 BatchConfigurer

import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;

@Configuration
public class DamengBatchConfigurer extends DefaultBatchConfigurer {

    private final DataSource dataSource;

    public DamengBatchConfigurer(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    protected JobRepository createJobRepository() throws Exception {
        JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTransactionManager(getTransactionManager());
        // 关键:告诉JobRepository,底层数据库可当作ORACLE处理
        factory.setDatabaseType(DatabaseType.ORACLE.getProductName());

        factory.afterPropertiesSet();
        return factory.getObject();
    }
}

测试作业

创建一个HelloWorldJobConfig.java


/**
 * Author: wxy97.com
 * Date: 2025/7/15 15:56
 * Description:
 */

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
public class HelloWorldJobConfig {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    // 1. 定义一个最简单的步骤 (Step),使用 Tasklet
    @Bean
    public Step helloWorldStep() {
        return stepBuilderFactory.get("helloWorldStep") // 给步骤命名
            .tasklet((contribution, chunkContext) -> {
                // 这是步骤要执行的逻辑
                System.out.println("======================================");
                System.out.println("Hello, Spring Batch!");
                System.out.println("======================================");
                return RepeatStatus.FINISHED; // 表示步骤已完成
            })
            .build();
    }

    // 2. 定义一个作业 (Job)
    @Bean
    public Job helloWorldJob() {
        return jobBuilderFactory.get("helloWorldJob") // 给作业命名
            .incrementer(new RunIdIncrementer()) // 使用这个增量器可以重复运行作业
            .start(helloWorldStep()) // 作业从这个步骤开始
            .build();
    }
}

修改application.yml 配置 指定启动时 执行的作业

  # --- Spring Batch 相关配置 ---
  # Spring Boot 默认会在启动时运行所有找到的Job Bean。
  # 为了防止意外运行,可以指定只运行某个特定的Job,或者完全禁用启动时运行。
  batch:
    jdbc:
      initialize-schema: NEVER
      platform: oracle
    job:
      # 启动时禁止运行任何作业(生产环境推荐),后续通过API或定时器触发
#      enabled: false
      # 启动时只运行名为 "helloWorldJob" 的作业
      names: helloWorldJob

启动项目

2025-07-15-ytrlouiy.webp

总结

通过以上步骤,我们系统性地解决了 Spring Batch 在达梦数据库上的一系列兼容性问题。核心要点可以总结为:

  • 禁用自动Schema:在 application.yml 中设置 spring.batch.jdbc.initialize-schema: NEVER

  • 手动执行脚本:使用修改后的 Oracle DDL 脚本在达梦数据库中手动创建元数据表。

  • 指定平台方言:通过 platform: oracle 和自定义 BatchConfigurer 告知 Spring Batch 使用 Oracle 的SQL语法进行交互。

遵循这套方案,就可以在项目中使用 Spring Batch 在达梦数据库上处理各种复杂的批量任务了。

参考

https://www.cnblogs.com/liaoyuanping-24/p/14956052.htmlhttps://stackoverflow.com/questions/52621792/initialise-h2-database-for-spring-batch-application