Spring Batch + Spring TaskScheduler example

本文介绍如何利用Spring TaskScheduler来定期执行批量任务,每5秒运行一次。使用Spring Batch读取CSV文件并显示其内容。示例包括配置、自定义写入器和运行程序。

http://www.mkyong.com/spring-batch/spring-batch-and-spring-taskscheduler-example/

In this tutorial, we will show you how to use Spring TaskScheduler to schedule a batch job to run every 5 seconds.

Tools and libraries used

  1. Maven 3
  2. Eclipse 4.2
  3. JDK 1.6
  4. Spring Core 3.2.2.RELEASE
  5. Spring Batch 2.2.0.RELEASE

1. Project Directory Structure

A standard Maven project.

spring-batch-taskscheduler

2. Spring TaskScheduler

Spring 3.0 introduces a TaskScheduler for scheduling tasks. It’s part of the Spring-Core, no need to declare an extra dependency.

<task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" fixed-delay="5000" />
  </task:scheduled-tasks>

  <task:scheduled-tasks>
<task:scheduled ref="runScheduler" method="run" cron="*/5 * * * * *" />
  </task:scheduled-tasks>

The TaskScheduler will schedule to run below bean.

RunScheduler.java
package com.mkyong;

import java.util.Date;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class RunScheduler {

  @Autowired
  private JobLauncher jobLauncher;

  @Autowired
  private Job job;

  public void run() {

    try {

	String dateParam = new Date().toString();
	JobParameters param =
	  new JobParametersBuilder().addString("date", dateParam).toJobParameters();

	System.out.println(dateParam);

	JobExecution execution = jobLauncher.run(job, param);
	System.out.println("Exit Status : " + execution.getStatus());

    } catch (Exception e) {
	e.printStackTrace();
    }

  }
}

P.S JobParamater need to be unique each time a batch job to run, for testing purpose, we just pass in a new Date()everything running the job.


3. Spring Batch Jobs

This job is just reading a csv file and display the value via a custom writer. Refer to the end of the file, we use task:scheduled-tasks to run this batch job every 5 seconds.

resources/spring/batch/jobs/job-report.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:batch="http://www.springframework.org/schema/batch"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/batch
	http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
	http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-3.2.xsd
	http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.2.xsd
	">

  <context:component-scan base-package="com.mkyong" />

  <!-- job context -->
  <bean id="jobRepository"
	class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
	<property name="transactionManager" ref="transactionManager" />
  </bean>

  <bean id="transactionManager"
	class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

  <bean id="jobLauncher"
	class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
	<property name="jobRepository" ref="jobRepository" />
  </bean>
  <!-- job context -->

  <bean id="report" class="com.mkyong.model.Report" scope="prototype" />

  <bean id="customWriter" class="com.mkyong.writers.CustomWriter" />

  <batch:job id="reportJob">
	<batch:step id="step1">
	  <batch:tasklet>
		<batch:chunk reader="cvsFileItemReader" writer="customWriter"
			commit-interval="10">
		</batch:chunk>
	  </batch:tasklet>
	</batch:step>
   </batch:job>

  <bean id="cvsFileItemReader"
        class="org.springframework.batch.item.file.FlatFileItemReader">

	<!-- Read a csv file -->
	<property name="resource" value="classpath:cvs/input/report.csv" />

	<property name="lineMapper">
	  <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
		<property name="lineTokenizer">
		  <bean
			class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
			<property name="names" value="id,impressions" />
		  </bean>
		</property>
		<property name="fieldSetMapper">
		  <bean
			class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
			<property name="prototypeBeanName" value="report" />
		  </bean>
		</property>
	  </bean>
	</property>

  </bean>

  <bean id="runScheduler" class="com.mkyong.RunScheduler" />

  <!-- Run every 5 seconds -->
  <task:scheduled-tasks>
    <!--
	<task:scheduled ref="runScheduler" method="run" fixed-delay="5000" />
    -->
	<task:scheduled ref="runScheduler" method="run" cron="*/5 * * * * *" />
   </task:scheduled-tasks>

</beans>
report.csv
1,"139,237"
2,"500,657"
3,"342,100"
CustomWriter.java
package com.mkyong.writers;

import java.util.List;
import org.springframework.batch.item.ItemWriter;
import com.mkyong.model.Report;

public class CustomWriter implements ItemWriter<Report> {

  @Override
  public void write(List<? extends Report> items) throws Exception {

	System.out.println("writer..." + items.size());
	for(Report item : items){
		System.out.println(item);
	}

  }

}

4. Run It

Loads the Spring application context, the scheduler will be run automatically.

App.java
package com.mkyong;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

  public static void main(String[] args) {

	String springConfig = "spring/batch/jobs/job-report.xml";

	ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);

  }
}

Output, it prints the csv content every 5 seconds.

......
Sun Jul 28 11:20:30 MYT 2013
Jul 28, 2013 11:20:30 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] launched with the following parameters: [{date=Sun Jul 28 11:20:30 MYT 2013}]
Jul 28, 2013 11:20:30 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
writer...3
Report [id=1, Impressions=139,237]
Report [id=2, Impressions=500,657]
Report [id=3, Impressions=342,100]
Jul 28, 2013 11:20:30 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] completed with the following parameters: [{date=Sun Jul 28 11:20:30 MYT 2013}] and the following status: [COMPLETED]
Exit Status : COMPLETED

Sun Jul 28 11:20:35 MYT 2013
Jul 28, 2013 11:20:35 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] launched with the following parameters: [{date=Sun Jul 28 11:20:35 MYT 2013}]
Jul 28, 2013 11:20:35 AM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [step1]
writer...3
Report [id=1, Impressions=139,237]
Report [id=2, Impressions=500,657]
Report [id=3, Impressions=342,100]
Exit Status : COMPLETED
Jul 28, 2013 11:20:35 AM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=reportJob]] completed with the following parameters: [{date=Sun Jul 28 11:20:35 MYT 2013}] and the following status: [COMPLETED]
......

<think>好的,我现在需要帮助用户解决如何将Spring Batch与MyBatis集成的问题。首先,我得回想一下Spring Batch的基本结构,它通常包括Job、Step、ItemReader、ItemProcessor和ItemWriter。而MyBatis是一个持久层框架,主要用于简化数据库操作,所以集成MyBatis可能涉及到在ItemReader或ItemWriter中使用MyBatis的Mapper。 接下来,我需要确认用户可能需要的步骤。首先,依赖配置是关键,Spring Boot项目通常使用Maven或Gradle,所以需要添加Spring Batch和MyBatis的依赖。查看用户提供的引用,引用[4]提到了Spring Data JDBC,但这里需要的是MyBatis,所以应该引导用户添加MyBatis Spring Boot Starter以及Spring Batch的依赖。可能还需要数据库驱动,比如H2或MySQL。 然后,配置数据源和MyBatis。在application.properties中设置数据库连接信息,并确保MyBatis的Mapper接口能被扫描到。用户可能需要使用@MapperScan注解,或者在每个Mapper接口上添加@Mapper注解。 接下来,定义Spring Batch的Job和Step。用户需要配置一个Job,并在其中定义具体的Step。每个Step通常包含Reader、Processor和Writer。这里可能需要创建自定义的ItemReader或ItemWriter,利用MyBatis的Mapper来读取或写入数据。 例如,在ItemReader中,可以注入MyBatis的Mapper接口,然后实现ItemReader接口,从Mapper中获取数据。同样地,ItemWriter可以使用Mapper的insert或update方法来写入数据。需要确保这些组件被正确注入,并且事务管理配置正确,可能涉及到@Transactional注解的使用,如引用[2]提到的AspectJ事务处理。 另外,需要考虑事务管理的问题。Spring Batch默认会管理事务,但结合MyBatis时需要确保配置正确。可能需要配置TransactionManager,确保MyBatis的操作在Spring的事务管理下进行。 测试也是一个重要环节,用户可能需要编写测试用例,使用Spring Batch的测试工具来验证集成的正确性。同时,处理异常和重试机制也是需要考虑的,比如使用Spring Batch的RetryTemplate。 还需要注意版本兼容性,引用[1]提到基于Spring Boot 2.X和JDK 8,所以需要确认依赖的版本是否匹配。例如,Spring Batch的版本是否与Spring Boot 2.X兼容,MyBatis Starter的版本是否适配。 可能的问题点包括依赖冲突、Mapper扫描不到、事务不生效等。需要引导用户检查依赖树,确保没有冲突;检查@MapperScan的位置是否正确;以及事务管理器的配置是否正确引用。 最后,提供示例代码会很有帮助,比如展示如何配置Job,如何编写使用MyBatis Mapper的Reader和Writer。同时,可以引用相关的文档或社区资源,如引用[3]中提到的Spring Social集成案例,可能对结构有参考价值。 总结步骤应该是:添加依赖、配置数据源和MyBatis、定义Batch Job和Step、实现MyBatis的Reader/Writer、处理事务和测试。确保每个步骤都清晰,并且用户能够按照指导逐步操作。</think>### 如何将Spring Batch与MyBatis集成使用? #### 1. **添加依赖** 首先在`pom.xml`中引入Spring Batch和MyBatis的依赖(以Spring Boot 2.X为例): ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> <!-- 根据Spring Boot版本调整 --> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <!-- 或其他数据库驱动 --> </dependency> ``` #### 2. **配置数据源与MyBatis** 在`application.properties`中配置数据库连接和MyBatis: ```properties spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= mybatis.mapper-locations=classpath:mapper/*.xml ``` 通过`@MapperScan`注解扫描MyBatis的Mapper接口: ```java @SpringBootApplication @MapperScan("com.example.mapper") public class MyApp { ... } ``` #### 3. **定义Spring Batch Job** 创建Job配置类,定义`Job`和`Step`: ```java @Configuration @EnableBatchProcessing public class BatchConfig { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; @Bean public Job myJob(Step myStep) { return jobBuilderFactory.get("myJob") .start(myStep) .build(); } @Bean public Step myStep(ItemReader<Data> reader, ItemWriter<Data> writer) { return stepBuilderFactory.get("myStep") .<Data, Data>chunk(10) .reader(reader) .writer(writer) .build(); } } ``` #### 4. **实现MyBatis的ItemReader/ItemWriter** - **ItemReader示例**(使用MyBatis Mapper查询数据): ```java public class MyBatisItemReader implements ItemReader<Data> { private final DataMapper dataMapper; private Iterator<Data> dataIterator; public MyBatisItemReader(DataMapper dataMapper) { this.dataMapper = dataMapper; } @Override public Data read() { if (dataIterator == null) { List<Data> dataList = dataMapper.selectUnprocessed(); dataIterator = dataList.iterator(); } return dataIterator.hasNext() ? dataIterator.next() : null; } } ``` - **ItemWriter示例**(使用MyBatis Mapper写入数据): ```java public class MyBatisItemWriter implements ItemWriter<Data> { private final DataMapper dataMapper; public MyBatisItemWriter(DataMapper dataMapper) { this.dataMapper = dataMapper; } @Override @Transactional public void write(List<? extends Data> items) { items.forEach(dataMapper::update); } } ``` #### 5. **事务管理** 确保在写入时启用事务支持,可结合Spring的`@Transactional`注解[^2]: ```java @Configuration public class TransactionConfig { @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } ``` #### 6. **测试与验证** 使用`@SpringBatchTest`进行集成测试: ```java @SpringBootTest @SpringBatchTest public class BatchIntegrationTest { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; @Test public void testJob() throws Exception { JobExecution jobExecution = jobLauncherTestUtils.launchJob(); assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus()); } } ``` #### 常见问题与优化 - **依赖冲突**:检查Spring Batch和MyBatis版本是否兼容。 - **事务回滚**:通过`@Transactional`控制事务边界。 - **性能优化**:调整`chunk`大小或使用分页查询。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值