Spring Batch on 达梦(Dameng):一篇全面的 ‘踩坑’ 与 ‘填坑’ 实战指南
编辑引言
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 自动配置的开关,一旦加上,JobBuilderFactory
、StepBuilderFactory
等核心组件就会被自动注册到容器中。
错误二: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
第二步:手动创建元数据表
这是最关键的一步。我们需要为达梦数据库准备一份建表脚本。
获取模板: 从 Spring Batch 的核心jar包 (
spring-batch-core-*.jar
) 的org/springframework/batch/core/
路径下,找到schema-oracle.sql
文件。修改脚本: 将其内容复制出来,并进行以下两处微调,使其更适合达梦数据库。
将所有
VARCHAR2(n char)
修改为VARCHAR(n)
。将所有序列的
START WITH 0
修改为START WITH 1
(最佳实践)。
指定模式: 为所有表名和序列名前面加上模式前缀,例如
IVS.
。在数据库执行sql 生成初始化表
第三步:(推荐) 自定义配置,确保运行时兼容
为了确保 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
启动项目
总结
通过以上步骤,我们系统性地解决了 Spring Batch 在达梦数据库上的一系列兼容性问题。核心要点可以总结为:
禁用自动Schema:在
application.yml
中设置spring.batch.jdbc.initialize-schema: NEVER
。手动执行脚本:使用修改后的 Oracle DDL 脚本在达梦数据库中手动创建元数据表。
指定平台方言:通过
platform: oracle
和自定义BatchConfigurer
告知 Spring Batch 使用 Oracle 的SQL语法进行交互。
遵循这套方案,就可以在项目中使用 Spring Batch 在达梦数据库上处理各种复杂的批量任务了。
参考
- 1
- 0
-
分享