Spring Batch_异步并发的processor && writer

本文介绍了如何使用Spring Batch优化批处理的效率,通过异步并发处理processor和writer来提高性能。当process过程处理时间较长时,多线程处理能显著提升效率。示例代码包括`spring-batch-async.xml`、`AsyncPeopleAddDescItemProcessor.java`和`AsyncPeopleAddDescItemWriter.java`。实验数据显示,相比无异步并发,处理100条数据的时间从213657ms缩短到108884ms。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring Batch_异步并发的processor && writer

普通的配置一个job,在这个demo中:http://my.oschina.net/xinxingegeya/blog/343190

job的reader是通过游标读取,commit-interval="2"表示每读取两条数据,就要进行process,process完成之后就要进行write,process和write是同步进行的,也就是说

必须process两条之后才能进行write,这两者不能异步进行。无疑,当process过程处理时间过长时,会拖慢整个过程的效率。还有process过程是single thread进行处理的,一个线程中处理两条数据

比用两个线程处理两条数据效率要慢的多(当处理一条数据花费的时间比较多时),这样会拖慢process过程的效率。

那么如何提高整个批处理过程的效率?

  1. 对于proceess和write过程异步化

  2. 在process过程使用多线程处理数据

主要的代码和配置:

spring-batch-async.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:batch="http://www.springframework.org/schema/batch"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 包的扫描 -->
	<context:component-scan base-package="com.lyx.batch" />

	<bean id="exceptionHandler" class="com.lyx.batch.ExceptionListener" />

	<batch:step id="abstractStep" abstract="true">
		<batch:listeners>
			<batch:listener ref="exceptionHandler" />
		</batch:listeners>
	</batch:step>
	<bean id="abstractCursorReader" abstract="true"
		class="org.springframework.batch.item.database.JdbcCursorItemReader">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<batch:job id="addPeopleDescJob">
		<batch:step id="addDescStep" parent="abstractStep">
			<batch:tasklet>
				<batch:chunk reader="peopleAddDescReader" processor="asyncProcessor"
					writer="asynWriter" commit-interval="2" />
			</batch:tasklet>
		</batch:step>
	</batch:jo
<think>我们正在讨论Spring Batch 5.2.2的使用。根据引用[3]的内容,我们知道Spring Batch是一个用于批量处理的强大框架,特别适合处理大数据量的任务。用户要求的是入门指南和使用教程,因此我们需要从基础开始,逐步介绍如何使用Spring Batch 5.2.2开发批处理任务。 我们将按照以下步骤进行: 1. 环境设置(使用Spring Boot集成Spring Batch 5.2.2) 2. 核心概念介绍(Job, Step, ItemReader, ItemProcessor, ItemWriter, Chunk等) 3. 开发一个简单的批处理任务(读取CSV文件,处理,写入数据库) 4. 配置和运行 5. 监控和测试 注意:由于用户指定了版本5.2.2,我们需要确保依赖的版本正确。 下面开始详细步骤: ### 1. 环境设置 使用Spring Boot来集成Spring Batch 5.2.2。Spring Boot版本需要与Spring Batch兼容,可以选择Spring Boot 3.x(要求Java 17+)或Spring Boot 2.7.x(Java 8+)。这里我们以Spring Boot 2.7.x为例(因为Spring Batch 5.x支持Spring Boot 2.x和3.x,但Spring Boot 3.x需要Spring Batch 5.x,且要求Java 17+)。 #### 创建项目 通过Spring Initializr(https://start.spring.io/)创建项目,选择: - Maven项目 - Java 8(或11,根据实际情况) - Spring Boot 2.7.x(这里我们选择2.7.18) - 依赖:Spring Batch, Spring Data JPA, H2 Database(或你选择的数据库) #### Maven依赖 确保pom.xml中包含Spring Batch的依赖,并且版本为5.2.2(可以通过Spring Boot的依赖管理自动匹配,也可以显式指定)。 Spring Boot 2.7.18默认集成的Spring Batch版本可能不是5.2.2,因此我们可以显式指定版本: ```xml <properties> <java.version>1.8</java.version> <spring-boot.version>2.7.18</spring-boot.version> <spring-batch.version>5.2.2</spring-batch.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-bom</artifactId> <version>${spring-batch.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` #### 配置数据库 Spring Batch需要数据库来存储作业的元数据(如作业执行状态、步骤执行状态等)。这里我们使用H2内存数据库,配置如下(application.properties): ```properties spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.h2.console.enabled=true spring.jpa.database-platform=org.hibernate.dialect.H2Dialect ``` ### 2. 核心概念 - **Job(作业)**:一个批处理任务,由多个Step组成。 - **Step(步骤)**:作业的一个步骤,可以是简单的任务(Tasklet)或基于分块的处理(Chunk-based)。 - **ItemReader**:读取数据,如从文件、数据库等。 - **ItemProcessor**:处理读取的数据,进行业务逻辑处理。 - **ItemWriter**:写入处理后的数据,如到数据库、文件等。 - **Chunk**:分块处理,每次处理一定数量的数据(如100条),然后提交事务。 ### 3. 开发一个简单的批处理任务 我们将创建一个任务:从CSV文件读取用户数据,将用户名转为大写,然后写入数据库。 #### 步骤1:创建实体类 ```java public class User { private Long id; private String name; private String email; // 构造器、Getter和Setter public User() { } public User(String name, String email) { this.name = name; this.email = email; } // 省略Getter和Setter } ``` #### 步骤2:创建Repository(可选,用于写入) 如果使用Spring Data JPA,可以创建Repository: ```java public interface UserRepository extends JpaRepository<User, Long> { } ``` #### 步骤3:配置批处理作业 创建一个配置类,定义Job和Step。 ```java import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder; import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; @Configuration @EnableBatchProcessing public class BatchConfiguration { @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; // 定义ItemReader:从CSV文件读取 @Bean public FlatFileItemReader<User> reader() { return new FlatFileItemReaderBuilder<User>() .name("userItemReader") .resource(new ClassPathResource("users.csv")) .delimited() .names("name", "email") .fieldSetMapper(new BeanWrapperFieldSetMapper<User>() {{ setTargetType(User.class); }}) .build(); } // 定义ItemProcessor:处理数据 @Bean public ItemProcessor<User, User> processor() { return user -> { user.setName(user.getName().toUpperCase()); return user; }; } // 定义ItemWriter:写入数据库(使用JPA) @Bean public ItemWriter<User> writer(UserRepository repository) { return items -> repository.saveAll(items); } // 定义Step @Bean public Step step1(ItemReader<User> reader, ItemProcessor<User, User> processor, ItemWriter<User> writer) { return stepBuilderFactory.get("step1") .<User, User>chunk(10) .reader(reader) .processor(processor) .writer(writer) .build(); } // 定义Job @Bean public Job importUserJob(Step step1) { return jobBuilderFactory.get("importUserJob") .start(step1) .build(); } } ``` #### 步骤4:准备数据文件 在src/main/resources下创建users.csv文件: ```csv John,john@example.com Jane,jane@example.com ``` #### 步骤5:创建数据库表 由于我们使用H2和JPA,可以通过实体类自动建表(在application.properties中配置): ```properties spring.jpa.hibernate.ddl-auto=create ``` ### 4. 运行和测试 启动Spring Boot应用,作业会自动运行(默认情况下,Spring Boot会在启动时运行所有作业一次)。你也可以通过命令行或REST API触发作业。 #### 测试 可以编写单元测试: ```java import org.junit.jupiter.api.Test; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class BatchJobTest { @Autowired private JobLauncher jobLauncher; @Autowired private Job importUserJob; @Test public void testBatchJob() throws Exception { JobExecution jobExecution = jobLauncher.run(importUserJob, new JobParameters()); // 验证作业执行状态 assertThat(jobExecution.getExitStatus().getExitCode()).isEqualTo("COMPLETED"); } } ``` ### 5. 监控 Spring Batch提供了作业执行的元数据,我们可以通过H2控制台查看(访问http://localhost:8080/h2-console): - 连接URL: jdbc:h2:mem:testdb - 用户名: sa - 密码: (空) 在H2控制台中,可以查看以下表来监控作业执行情况: - BATCH_JOB_INSTANCE - BATCH_JOB_EXECUTION - BATCH_STEP_EXECUTION ### 总结 以上是一个使用Spring Batch 5.2.2的简单入门示例。我们创建了一个从CSV文件读取数据、处理数据并写入数据库的批处理任务。Spring Batch提供了强大的批处理功能,包括事务管理、错误处理、跳过和重试机制、并行处理等,可以满足企业级批处理需求。 ### §§相关问题§§ 1. 如何在Spring Batch中实现错误处理(如跳过失败记录)? 2. 如何配置Spring Batch作业的定时执行? 3. Spring Batch如何支持多线程和分区处理以提升性能?</think>### Spring Batch 5.2.2 入门指南与使用教程 Spring Batch 5.2.2 是当前主流的企业级批处理框架,专注于高效处理大规模数据任务(如ETL、报表生成、数据清洗)。以下是基于最新版本的完整开发指南: --- ### 一、环境配置(Spring Boot 3.x + Java 17) #### 1. Maven 依赖 ```xml <properties> <spring-boot.version>3.2.0</spring-boot.version> <spring-batch.version>5.2.2</spring-batch.version> </properties> <dependencies> <!-- Spring Batch 核心 --> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-core</artifactId> <version>${spring-batch.version}</version> </dependency> <!-- 与Spring Boot集成 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> <!-- 数据库支持(以H2为例) --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies> ``` #### 2. 元数据表配置 Spring Batch 需要数据库存储作业状态元数据。在 `application.yml` 中配置: ```yaml spring: batch: jdbc: initialize-schema: always # 自动创建元数据表 datasource: url: jdbc:h2:mem:testdb driver-class-name: org.h2.Driver username: sa password: "" ``` --- ### 二、核心组件开发(以CSV转数据库为例) #### 1. 数据模型定义 ```java public record Person(String name, int age, String email) {} ``` #### 2. 批处理作业配置 ```java @Configuration @EnableBatchProcessing public class BatchConfig { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; // 1. 读取CSV文件 @Bean public FlatFileItemReader<Person> reader() { return new FlatFileItemReaderBuilder<Person>() .name("personItemReader") .resource(new ClassPathResource("data.csv")) .delimited() .names("name", "age", "email") .fieldSetMapper(new BeanWrapperFieldSetMapper<>() {{ setTargetType(Person.class); }}) .build(); } // 2. 数据处理(年龄校验) @Bean public ItemProcessor<Person, Person> processor() { return person -> { if (person.age() < 0) throw new IllegalArgumentException("年龄无效"); return new Person(person.name().toUpperCase(), person.age(), person.email()); }; } // 3. 写入数据库 @Bean public JdbcBatchItemWriter<Person> writer(DataSource dataSource) { return new JdbcBatchItemWriterBuilder<Person>() .dataSource(dataSource) .sql("INSERT INTO people(name, age, email) VALUES (:name, :age, :email)") .beanMapped() .build(); } // 4. 定义步骤(分块处理) @Bean public Step processStep(ItemReader<Person> reader, ItemProcessor<Person, Person> processor, ItemWriter<Person> writer) { return stepBuilderFactory.get("processStep") .<Person, Person>chunk(100) // 每100条提交一次事务 .reader(reader) .processor(processor) .writer(writer) .faultTolerant() .skipLimit(10) // 最多跳过10条错误数据 .skip(IllegalArgumentException.class) .build(); } // 5. 定义作业 @Bean public Job importPersonJob(Step processStep) { return jobBuilderFactory.get("importPersonJob") .start(processStep) .build(); } } ``` --- ### 三、高级特性 #### 1. 多线程处理(提升吞吐量) ```java @Bean public Step parallelStep() { return stepBuilderFactory.get("parallelStep") .<Person, Person>chunk(100) .reader(reader()) .processor(processor()) .writer(writer()) .taskExecutor(new SimpleAsyncTaskExecutor()) // 启用异步 .throttleLimit(8) // 并发线程数 .build(); } ``` #### 2. 分区处理(大数据集分割) ```java @Bean public Step partitionedStep() { return stepBuilderFactory.get("partitionedStep") .partitioner("slaveStep", partitioner()) .step(slaveStep()) .gridSize(4) // 分区数量 .taskExecutor(new SimpleAsyncTaskExecutor()) .build(); } ``` --- ### 四、运行与监控 #### 1. 启动作业 ```java @Autowired private JobLauncher jobLauncher; @Autowired private Job importPersonJob; public void runJob() throws Exception { JobParameters params = new JobParametersBuilder() .addLong("time", System.currentTimeMillis()) .toJobParameters(); jobLauncher.run(importPersonJob, params); } ``` #### 2. 监控元数据表 通过H2控制台(`http://localhost:8080/h2-console`)查看关键表: - `BATCH_JOB_INSTANCE`:作业实例 - `BATCH_STEP_EXECUTION`:步骤执行状态 - `BATCH_JOB_EXECUTION_PARAMS`:作业参数 --- ### 五、最佳实践 1. **性能优化**: - 调整 `chunk size` 平衡内存与I/O - 使用 `JdbcCursorItemReader` 替代分页查询 - 启用批处理写操作(`writer.setAssertUpdates(false)`) 2. **错误处理**: ```java .faultTolerant() .retryLimit(3) .retry(SQLException.class) .skipPolicy(new AlwaysSkipItemSkipPolicy()) ``` 3. **云原生支持**: - 通过Kubernetes Job调度批处理任务 - 使用Spring Cloud Task管理作业生命周期 > 完整示例代码参考:[Spring Batch Samples](https://github.com/spring-projects/spring-batch/tree/main/spring-batch-samples) [^3] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值