Spring Batch中的块处理

大数据集的处理是软件世界中最重要的问题之一。 Spring Batch是一个轻量级且强大的批处理框架,用于处理数据集。

Spring Batch Framework提供了“面向TaskletStep”和“面向块”的处理风格。 在本文中,将解释面向块的处理模型。 此外,绝对建议在Spring Batch中使用面向TaskletStep的处理在本文中,绝对建议您研究如何在Spring Batch中开发面向TaskletStep的处理。

Spring Batch v2.0附带了面向块的处理功能。 它是指一次读取一个数据,并在事务边界内创建要写出的“块”。 从ItemReader读取一项,并将其交给ItemProcessor并写入。 一旦读取的项目数等于提交间隔,就通过ItemWriter写入整个块,然后提交事务。

基本上,如果需要至少一个数据项的读写,则应使用此功能。 否则,如果只需要读取或写入数据项,则可以使用面向TaskletStep的处理。

面向块的处理模型通过org.springframework.batch.item包公开了三个重要的接口,分别是ItemReaderItemProcessorItemWriter

  • ItemReader:此接口用于提供数据。 它读取将要处理的数据。
  • ItemProcessor:此接口用于项目转换。 它处理输入对象并转换为输出对象。
  • ItemWriter:此接口用于常规输出操作。 它写入由ItemProcessor转换的数据。 例如,可以将数据写入数据库,内存或输出流(等)。 在此示例应用程序中,我们将写入数据库。

让我们看一下如何开发面向块的处理模型。

二手技术:

  • JDK 1.7.0_09
  • Spring3.1.3
  • Spring批次2.1.9
  • 休眠4.1.8
  • Tomcat JDBC 7.0.27
  • MySQL 5.5.8
  • MySQL连接器5.1.17
  • Maven的3.0.4

步骤1:建立已完成的专案

创建一个Maven项目,如下所示。 (可以使用Maven或IDE插件来创建它)。

步骤2:图书馆

通过执行以下脚本来创建新的用户表:

CREATE TABLE ONLINETECHVISION.USER (id int(11) NOT NULL AUTO_INCREMENT,name varchar(45) NOT NULL,surname varchar(45) NOT NULL,PRIMARY KEY (`id`)
);

步骤3:图书馆

首先,将依赖项添加到Maven的pom.xml中。

<properties><spring.version>3.1.3.RELEASE</spring.version><spring-batch.version>2.1.9.RELEASE</spring-batch.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency>    <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.batch</groupId><artifactId>spring-batch-core</artifactId><version>${spring-batch.version}</version></dependency><!-- Hibernate dependencies --><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>4.1.8.Final</version></dependency><!-- Tomcat DBCP --><dependency><groupId>org.apache.tomcat</groupId><artifactId>tomcat-jdbc</artifactId><version>7.0.27</version></dependency><!-- MySQL Java Connector library --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.17</version></dependency><!-- Log4j library --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.16</version></dependency></dependencies>

maven-compiler-plugin (Maven插件)用于使用JDK 1.7编译项目

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.0</version><configuration><source>1.7</source><target>1.7</target></configuration></plugin>

以下Maven插件可用于创建runnable-jar

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.0</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><configuration><source>1.7</source><target>1.7</target></configuration><transformers><transformerimplementation='org.apache.maven.plugins.shade.resource.
ManifestResourceTransformer'><mainClass>com.onlinetechvision.exe.Application</mainClass></transformer><transformerimplementation='org.apache.maven.plugins.shade.resource.
AppendingTransformer'><resource>META-INF/spring.handlers</resource></transformer><transformerimplementation='org.apache.maven.plugins.shade.resource.
AppendingTransformer'><resource>META-INF/spring.schemas</resource></transformer></transformers></configuration></execution></executions></plugin>

步骤4:建立使用者实体

用户实体已创建。 该实体将在处理后存储。

package com.onlinetechvision.user;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;/*** User Entity** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
@Entity
@Table(name='USER')
public class User {private int id;private String name;private String surname;@Id@GeneratedValue(strategy=GenerationType.AUTO)@Column(name='ID', unique = true, nullable = false)public int getId() {return id;}public void setId(int id) {this.id = id;}@Column(name='NAME', unique = true, nullable = false)public String getName() {return name;}public void setName(String name) {this.name = name;}@Column(name='SURNAME', unique = true, nullable = false)public String getSurname() {return surname;}public void setSurname(String surname) {this.surname = surname;}   @Overridepublic String toString() {StringBuffer strBuff = new StringBuffer();strBuff.append('id : ').append(getId());strBuff.append(', name : ').append(getName());strBuff.append(', surname : ').append(getSurname());return strBuff.toString();}
}

步骤5:建立IUserDAO介面

创建IUserDAO接口以公开数据访问功能。

package com.onlinetechvision.user.dao;import java.util.List;import com.onlinetechvision.user.User;/*** User DAO Interface** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public interface IUserDAO {/*** Adds User** @param  User user*/void addUser(User user);/*** Gets User List**/List<User> getUsers();
}

步骤6:建立UserDAO IMPL

通过实现IUserDAO接口创建UserDAO类。

package com.onlinetechvision.user.dao;import java.util.List;import org.hibernate.SessionFactory;import com.onlinetechvision.user.User;/*** User DAO** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class UserDAO implements IUserDAO {private SessionFactory sessionFactory;/*** Gets Hibernate Session Factory** @return SessionFactory - Hibernate Session Factory*/public SessionFactory getSessionFactory() {return sessionFactory;}/*** Sets Hibernate Session Factory** @param SessionFactory - Hibernate Session Factory*/public void setSessionFactory(SessionFactory sessionFactory) {this.sessionFactory = sessionFactory;}/*** Adds User** @param  User user*/@Overridepublic void addUser(User user) {getSessionFactory().getCurrentSession().save(user);}/*** Gets User List** @return List - User list*/@SuppressWarnings({ 'unchecked' })@Overridepublic List<User> getUsers() {List<User> list = getSessionFactory().getCurrentSession().createQuery('from User').list();return list;}}

步骤7:建立IUserService介面

为服务层创建了IUserService接口。

package com.onlinetechvision.user.service;import java.util.List;import com.onlinetechvision.user.User;/**** User Service Interface** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public interface IUserService {/*** Adds User** @param  User user*/void addUser(User user);/*** Gets User List** @return List - User list*/List<User> getUsers();
}

步骤8:创建UserService IMPL

通过实现IUserService接口创建UserService类。

package com.onlinetechvision.user.service;import java.util.List;import org.springframework.transaction.annotation.Transactional;import com.onlinetechvision.user.User;
import com.onlinetechvision.user.dao.IUserDAO;/**** User Service** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
@Transactional(readOnly = true)
public class UserService implements IUserService {IUserDAO userDAO;/*** Adds User** @param  User user*/@Transactional(readOnly = false)@Overridepublic void addUser(User user) {getUserDAO().addUser(user);}/*** Gets User List**/@Overridepublic List<User> getUsers() {return getUserDAO().getUsers();}public IUserDAO getUserDAO() {return userDAO;}public void setUserDAO(IUserDAO userDAO) {this.userDAO = userDAO;}
}

步骤9:建立TestReader IMPL

TestReader类是通过实现ItemReader接口创建的。 调用该类是为了读取项目。 当read方法返回null时,读取操作完成。 以下步骤详细说明了如何执行firstJob。

firstjob的commit-interval值为2,并执行以下步骤:

1)调用firstTestReader以读取第一项(firstname_0,firstsurname_0)
2)再次调用firstTestReader以读取第二个项目(firstname_1,firstsurname_1)
3)调用testProcessor处理第一项(FIRSTNAME_0,FIRSTSURNAME_0) 4)调用testProcessor处理第二个项目(FIRSTNAME_1,FIRSTSURNAME_1) 5)调用testWriter将第一项(FIRSTNAME_0,FIRSTSURNAME_0)写入数据库 6)调用testWriter将第二项(FIRSTNAME_1,FIRSTSURNAME_1)写入数据库 7)提交第一项和第二项,并且关闭交易。 调用firstTestReader以读取第三项(firstname_2,firstsurname_2) 9)firstTestReader的maxIndex值为3。read方法返回null,并且项读取操作完成。 10)调用testProcessor处理第三项(FIRSTNAME_2,FIRSTSURNAME_2) 11)调用testWriter将第一项(FIRSTNAME_2,FIRSTSURNAME_2)写入数据库 12)第三项已提交,交易已关闭。

第一步已完成,状态为“已完成”,第二步已开始。 secondJob和thirdJob以相同的方式执行。

package com.onlinetechvision.item;import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;import com.onlinetechvision.user.User;/*** TestReader Class is created to read items which will be processed** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class TestReader implements ItemReader<User> {private int index;private int maxIndex;private String namePrefix;private String surnamePrefix;/*** Reads items one by one** @return User** @throws Exception* @throws UnexpectedInputException* @throws ParseException* @throws NonTransientResourceException**/@Overridepublic User read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {User user = new User();user.setName(getNamePrefix() + '_' + index);user.setSurname(getSurnamePrefix() + '_' + index);if(index > getMaxIndex()) {return null;}incrementIndex();return user;}/*** Increments index which defines read-count** @return int**/private int incrementIndex() {return index++;}public int getMaxIndex() {return maxIndex;}public void setMaxIndex(int maxIndex) {this.maxIndex = maxIndex;}public String getNamePrefix() {return namePrefix;}public void setNamePrefix(String namePrefix) {this.namePrefix = namePrefix;}public String getSurnamePrefix() {return surnamePrefix;}public void setSurnamePrefix(String surnamePrefix) {this.surnamePrefix = surnamePrefix;}}

步骤10:创建FailedCaseTestReader IMPL

创建FailedCaseTestReader类以模拟失败的作业状态。 在此示例应用程序中,当在thirdStep处理thirdJob时,将调用failedCaseTestReader并引发异常,因此其状态将为FAILED。

package com.onlinetechvision.item;import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;import com.onlinetechvision.user.User;/*** FailedCaseTestReader Class is created in order to simulate the failed job status.** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class FailedCaseTestReader implements ItemReader<User> {private int index;private int maxIndex;private String namePrefix;private String surnamePrefix;/*** Reads items one by one** @return User** @throws Exception* @throws UnexpectedInputException* @throws ParseException* @throws NonTransientResourceException**/@Overridepublic User read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {User user = new User();user.setName(getNamePrefix() + '_' + index);user.setSurname(getSurnamePrefix() + '_' + index);if(index >= getMaxIndex()) {throw new Exception('Unexpected Error!');}incrementIndex();return user;}/*** Increments index which defines read-count** @return int**/private int incrementIndex() {return index++;}public int getMaxIndex() {return maxIndex;}public void setMaxIndex(int maxIndex) {this.maxIndex = maxIndex;}public String getNamePrefix() {return namePrefix;}public void setNamePrefix(String namePrefix) {this.namePrefix = namePrefix;}public String getSurnamePrefix() {return surnamePrefix;}public void setSurnamePrefix(String surnamePrefix) {this.surnamePrefix = surnamePrefix;}}

步骤11:创建TestProcessor IMPL

通过实现ItemProcessor接口来创建TestProcessor类。 此类称为处理项目。 从TestReader接收用户项,对其进行处理并返回给TestWriter。

package com.onlinetechvision.item;import java.util.Locale;import org.springframework.batch.item.ItemProcessor;import com.onlinetechvision.user.User;/*** TestProcessor Class is created to process items.** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class TestProcessor implements ItemProcessor<User, User>  {/*** Processes items one by one** @param User user* @return User* @throws Exception**/@Overridepublic User process(User user) throws Exception {user.setName(user.getName().toUpperCase(Locale.ENGLISH));user.setSurname(user.getSurname().toUpperCase(Locale.ENGLISH));return user;}}

步骤12:建立TestWriter IMPL

TestWriter类是通过实现ItemWriter接口创建的。 此类称为将项目写入DB,内存等…

package com.onlinetechvision.item;import java.util.List;import org.springframework.batch.item.ItemWriter;import com.onlinetechvision.user.User;
import com.onlinetechvision.user.service.IUserService;/*** TestWriter Class is created to write items to DB, memory etc...** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class TestWriter implements ItemWriter<User> {private IUserService userService;/*** Writes items via list** @throws Exception**/@Overridepublic void write(List<? extends User> userList) throws Exception {for(User user : userList) {getUserService().addUser(user);}System.out.println('User List : ' + getUserService().getUsers());}public IUserService getUserService() {return userService;}public void setUserService(IUserService userService) {this.userService = userService;}}

步骤13:创建失败的StepTasklet类

通过实现Tasklet接口创建FailedStepTasklet 。 它说明了失败步骤中的业务逻辑。

package com.onlinetechvision.tasklet;import org.apache.log4j.Logger;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;/*** FailedStepTasklet Class illustrates a failed job.** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class FailedStepTasklet implements Tasklet {private static final Logger logger = Logger.getLogger(FailedStepTasklet.class);private String taskResult;/*** Executes FailedStepTasklet** @param StepContribution stepContribution* @param ChunkContext chunkContext* @return RepeatStatus* @throws Exception**/public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {logger.debug('Task Result : ' + getTaskResult());throw new Exception('Error occurred!');}public String getTaskResult() {return taskResult;}public void setTaskResult(String taskResult) {this.taskResult = taskResult;} }

步骤14:创建BatchProcessStarter类

创建BatchProcessStarter类以启动作业。 此外,它记录他们的执行结果。

package com.onlinetechvision.spring.batch;import org.apache.log4j.Logger;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;/*** BatchProcessStarter Class launches the jobs and logs their execution results.** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class BatchProcessStarter {private static final Logger logger = Logger.getLogger(BatchProcessStarter.class);private Job firstJob;private Job secondJob;private Job thirdJob;private JobLauncher jobLauncher;private JobRepository jobRepository;/*** Starts the jobs and logs their execution results.**/public void start() {JobExecution jobExecution = null;JobParametersBuilder builder = new JobParametersBuilder();try {getJobLauncher().run(getFirstJob(), builder.toJobParameters());jobExecution = getJobRepository().getLastJobExecution(getFirstJob().getName(), builder.toJobParameters());logger.debug(jobExecution.toString());			getJobLauncher().run(getSecondJob(), builder.toJobParameters());jobExecution = getJobRepository().getLastJobExecution(getSecondJob().getName(), builder.toJobParameters());logger.debug(jobExecution.toString());getJobLauncher().run(getThirdJob(), builder.toJobParameters());jobExecution = getJobRepository().getLastJobExecution(getThirdJob().getName(), builder.toJobParameters());logger.debug(jobExecution.toString());} catch (JobExecutionAlreadyRunningException| JobRestartException| JobInstanceAlreadyCompleteException| JobParametersInvalidException e) {logger.error(e);}}	public Job getFirstJob() {return firstJob;}public void setFirstJob(Job firstJob) {this.firstJob = firstJob;}public Job getSecondJob() {return secondJob;}public void setSecondJob(Job secondJob) {this.secondJob = secondJob;}	public Job getThirdJob() {return thirdJob;}public void setThirdJob(Job thirdJob) {this.thirdJob = thirdJob;}public JobLauncher getJobLauncher() {return jobLauncher;}public void setJobLauncher(JobLauncher jobLauncher) {this.jobLauncher = jobLauncher;}public JobRepository getJobRepository() {return jobRepository;}public void setJobRepository(JobRepository jobRepository) {this.jobRepository = jobRepository;}	}

步骤15:创建dataContext.xml

jdbc.properties已创建。 它定义数据源信息,并通过dataContext.xml读取

jdbc.db.driverClassName=com.mysql.jdbc.Driver
jdbc.db.url=jdbc:mysql://localhost:3306/onlinetechvision
jdbc.db.username=root
jdbc.db.password=root
jdbc.db.initialSize=10
jdbc.db.minIdle=3
jdbc.db.maxIdle=10
jdbc.db.maxActive=10
jdbc.db.testWhileIdle=true
jdbc.db.testOnBorrow=true
jdbc.db.testOnReturn=true
jdbc.db.initSQL=SELECT 1 FROM DUAL
jdbc.db.validationQuery=SELECT 1 FROM DUAL
jdbc.db.timeBetweenEvictionRunsMillis=30000

步骤16:创建dataContext.xml

Spring配置文件dataContext.xml已创建。 它涵盖了dataSource,sessionFactory和transactionManager定义。

<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns='http://www.springframework.org/schema/beans'xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xmlns:context='http://www.springframework.org/schema/context'xmlns:p='http://www.springframework.org/schema/p'xmlns:batch='http://www.springframework.org/schema/batch'xmlns:tx='http://www.springframework.org/schema/tx'xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.1.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd'><context:property-placeholder location='classpath:jdbc.properties'/><!-- Enable the configuration of transactional behavior based on annotations --><tx:annotation-driven transaction-manager='transactionManager'/><!-- Data Source Declaration --><bean id='dataSource' class='org.apache.tomcat.jdbc.pool.DataSource' destroy-method='close'p:driverClassName='${jdbc.db.driverClassName}'p:url='${jdbc.db.url}'p:username='${jdbc.db.username}'p:password='${jdbc.db.password}'p:initialSize='${jdbc.db.initialSize}'p:minIdle='${jdbc.db.minIdle}'p:maxIdle='${jdbc.db.maxIdle}'p:maxActive='${jdbc.db.maxActive}'p:testWhileIdle='${jdbc.db.testWhileIdle}'p:testOnBorrow='${jdbc.db.testOnBorrow}'p:testOnReturn='${jdbc.db.testOnReturn}'p:initSQL='${jdbc.db.initSQL}'p:validationQuery='${jdbc.db.validationQuery}'p:timeBetweenEvictionRunsMillis='${jdbc.db.timeBetweenEvictionRunsMillis}'/>	<!-- Session Factory Declaration --><bean id='sessionFactory' class='org.springframework.orm.hibernate4.LocalSessionFactoryBean'><property name='dataSource' ref='dataSource' /><property name='annotatedClasses'><list><value>com.onlinetechvision.user.User</value></list></property><property name='hibernateProperties'><props><prop key='hibernate.dialect'>org.hibernate.dialect.MySQLDialect</prop><prop key='hibernate.show_sql'>true</prop></props></property></bean><!-- Transaction Manager Declaration --><bean id='transactionManager' class='org.springframework.orm.hibernate4.HibernateTransactionManager'><property name='sessionFactory' ref='sessionFactory'/></bean></beans>

步骤17:创建jobContext.xml

Spring配置文件jobContext.xml已创建。 它涵盖jobRepository,jobLauncher,项目读取器,项目处理器,项目编写器,tasklet和作业定义。

<?xml version='1.0' encoding='UTF-8'?>
<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'xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.1.xsd'><import resource='dataContext.xml'/><!-- jobRepository Declaration --><bean id='jobRepository' class='org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean'><property name='transactionManager' ref='transactionManager' /></bean><!-- jobLauncher Declaration --><bean id='jobLauncher' class='org.springframework.batch.core.launch.support.SimpleJobLauncher' ><property name='jobRepository' ref='jobRepository'/></bean><!-- Reader Bean Declarations --><bean id='firstTestReader' class='com.onlinetechvision.item.TestReader'><property name='maxIndex' value='2'/><property name='namePrefix' value='firstname'/><property name='surnamePrefix' value='firstsurname'/></bean><bean id='secondTestReader' class='com.onlinetechvision.item.TestReader'><property name='maxIndex' value='2'/><property name='namePrefix' value='secondname'/><property name='surnamePrefix' value='secondsurname'/></bean><bean id='thirdTestReader' class='com.onlinetechvision.item.TestReader'><property name='maxIndex' value='3'/><property name='namePrefix' value='thirdname'/><property name='surnamePrefix' value='thirdsurname'/></bean><bean id='fourthTestReader' class='com.onlinetechvision.item.TestReader'><property name='maxIndex' value='3'/><property name='namePrefix' value='fourthname'/><property name='surnamePrefix' value='fourthsurname'/></bean><bean id='fifthTestReader' class='com.onlinetechvision.item.TestReader'><property name='maxIndex' value='3'/><property name='namePrefix' value='fifthname'/><property name='surnamePrefix' value='fifthsurname'/></bean><bean id='failedCaseTestReader' class='com.onlinetechvision.item.FailedCaseTestReader'><property name='maxIndex' value='1'/><property name='namePrefix' value='failedcasename'/><property name='surnamePrefix' value='failedcasesurname'/></bean><!-- Processor Bean Declaration --><bean id='testProcessor' class='com.onlinetechvision.item.TestProcessor' /><!-- Writer Bean Declaration --><bean id='testWriter' class='com.onlinetechvision.item.TestWriter' ><property name='userService' ref='userService'/></bean><!-- Failed Step Tasklet Declaration --><bean id='failedStepTasklet' class='com.onlinetechvision.tasklet.FailedStepTasklet'><property name='taskResult'  value='Error occurred!' /></bean> <!-- Batch Job Declarations --><batch:job id='firstJob'><batch:step id='firstStep' next='secondStep'><batch:tasklet><batch:chunk reader='firstTestReader' processor='testProcessor' writer='testWriter' commit-interval='2'/></batch:tasklet></batch:step><batch:step id='secondStep'><batch:tasklet><batch:chunk reader='secondTestReader' processor='testProcessor' writer='testWriter' commit-interval='2'/></batch:tasklet></batch:step></batch:job><batch:job id='secondJob'><batch:step id='thirdStep'><batch:tasklet><batch:chunk reader='thirdTestReader' processor='testProcessor' writer='testWriter' commit-interval='2'/></batch:tasklet><batch:next on='*' to='fourthStep' /><batch:next on='FAILED' to='firstFailedStep' /></batch:step><batch:step id='fourthStep'><batch:tasklet><batch:chunk reader='fourthTestReader' processor='testProcessor' writer='testWriter' commit-interval='2'/></batch:tasklet></batch:step><batch:step id='firstFailedStep'><batch:tasklet ref='failedStepTasklet' /></batch:step></batch:job><batch:job id='thirdJob'><batch:step id='fifthStep'><batch:tasklet><batch:chunk reader='failedCaseTestReader' processor='testProcessor' writer='testWriter' commit-interval='2'/></batch:tasklet><batch:next on='*' to='sixthStep' /><batch:next on='FAILED' to='secondFailedStep' /></batch:step><batch:step id='sixthStep'><batch:tasklet><batch:chunk reader='fifthTestReader' processor='testProcessor' writer='testWriter' commit-interval='2'/></batch:tasklet></batch:step><batch:step id='secondFailedStep'><batch:tasklet ref='failedStepTasklet' /></batch:step></batch:job></beans>

步骤18:创建applicationContext.xml

Spring配置文件applicationContext.xml已创建。 它涵盖了bean的定义。

<?xml version='1.0' encoding='UTF-8'?>
<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'xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.1.xsd'><import resource='jobContext.xml'/><!-- User DAO Declaration --><bean id='userDAO' class='com.onlinetechvision.user.dao.UserDAO'><property name='sessionFactory' ref='sessionFactory' /></bean><!-- User Service Declaration --><bean id='userService' class='com.onlinetechvision.user.service.UserService'><property name='userDAO' ref='userDAO' /></bean>	<!-- BatchProcessStarter Declaration --><bean id='batchProcessStarter' class='com.onlinetechvision.spring.batch.BatchProcessStarter'><property name='jobLauncher' ref='jobLauncher'/><property name='jobRepository' ref='jobRepository'/><property name='firstJob' ref='firstJob'/><property name='secondJob' ref='secondJob'/><property name='thirdJob' ref='thirdJob'/></bean> </beans>

步骤19:创建应用程序类

创建应用程序类以运行应用程序。

package com.onlinetechvision.exe;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import com.onlinetechvision.spring.batch.BatchProcessStarter;/*** Application Class starts the application.** @author onlinetechvision.com* @since 10 Dec 2012* @version 1.0.0**/
public class Application {/*** Starts the application** @param  String[] args**/public static void main(String[] args) {ApplicationContext appContext = new ClassPathXmlApplicationContext('applicationContext.xml');BatchProcessStarter batchProcessStarter = (BatchProcessStarter)appContext.getBean('batchProcessStarter');batchProcessStarter.start();}}

步骤20:建立专案

构建OTV_SpringBatch_Chunk_Oriented_Processing项目之后,将创建OTV_SpringBatch_Chunk_Oriented_Processing-0.0.1-SNAPSHOT.jar

步骤21:运行项目

运行创建的OTV_SpringBatch_Chunk_Oriented_Processing-0.0.1-SNAPSHOT.jar文件后,将显示以下数据库和控制台输出日志:

数据库截图:

First Job的控制台输出:

16.12.2012 19:30:41  INFO (SimpleJobLauncher.java:118) - Job: [FlowJob: [name=firstJob]] launched with the following parameters: [{}]16.12.2012 19:30:41 DEBUG (AbstractJob.java:278) - Job execution starting: JobExecution: id=0, version=0, startTime=null, endTime=null, lastUpdated=Sun Dec 16 19:30:41 GMT 2012, status=STARTING, exitStatus=exitCode=UNKNOWN;exitDescription=, job=[JobInstance: id=0, version=0, JobParameters=[{}], Job=[firstJob]]User List : [id : 181, name : FIRSTNAME_0, surname : FIRSTSURNAME_0, id : 182, name : FIRSTNAME_1, surname : FIRSTSURNAME_1, id : 183, name : FIRSTNAME_2, surname : FIRSTSURNAME_2, id : 184, name : SECONDNAME_0, surname : SECONDSURNAME_0, id : 185, name : SECONDNAME_1, surname : SECONDSURNAME_1, id : 186, name : SECONDNAME_2, surname : SECONDSURNAME_2]16.12.2012 19:30:42 DEBUG (BatchProcessStarter.java:43) - JobExecution: id=0, version=2, startTime=Sun Dec 16 19:30:41 GMT 2012, endTime=Sun Dec 16 19:30:42 GMT 2012, lastUpdated=Sun Dec 16 19:30:42 GMT 2012, status=COMPLETED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=0, version=0, JobParameters=[{}], Job=[firstJob]]

Second Job的控制台输出:

16.12.2012 19:30:42  INFO (SimpleJobLauncher.java:118) - Job: [FlowJob: [name=secondJob]] launched with the following parameters: [{}]16.12.2012 19:30:42 DEBUG (AbstractJob.java:278) - Job execution starting: JobExecution: id=1, version=0, startTime=null, endTime=null, lastUpdated=Sun Dec 16 19:30:42 GMT 2012, status=STARTING, exitStatus=exitCode=UNKNOWN;exitDescription=, job=[JobInstance: id=1, version=0, JobParameters=[{}], Job=[secondJob]]User List : [id : 181, name : FIRSTNAME_0, surname : FIRSTSURNAME_0, id : 182, name : FIRSTNAME_1, surname : FIRSTSURNAME_1, id : 183, name : FIRSTNAME_2, surname : FIRSTSURNAME_2, id : 184, name : SECONDNAME_0, surname : SECONDSURNAME_0, id : 185, name : SECONDNAME_1, surname : SECONDSURNAME_1, id : 186, name : SECONDNAME_2, surname : SECONDSURNAME_2, id : 187, name : THIRDNAME_0, surname : THIRDSURNAME_0, id : 188, name : THIRDNAME_1, surname : THIRDSURNAME_1, id : 189, name : THIRDNAME_2, surname : THIRDSURNAME_2, id : 190, name : THIRDNAME_3, surname : THIRDSURNAME_3, id : 191, name : FOURTHNAME_0, surname : FOURTHSURNAME_0, id : 192, name : FOURTHNAME_1, surname : FOURTHSURNAME_1, id : 193, name : FOURTHNAME_2, surname : FOURTHSURNAME_2, id : 194, name : FOURTHNAME_3, surname : FOURTHSURNAME_3]16.12.2012 19:30:42 DEBUG (BatchProcessStarter.java:47) - JobExecution: id=1, version=2, startTime=Sun Dec 16 19:30:42 GMT 2012, endTime=Sun Dec 16 19:30:42 GMT 2012, lastUpdated=Sun Dec 16 19:30:42 GMT 2012, status=COMPLETED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=1, version=0, JobParameters=[{}], Job=[secondJob]]

Third Job的控制台输出:

16.12.2012 19:30:42  INFO (SimpleJobLauncher.java:118) - Job: [FlowJob: [name=thirdJob]] launched with the following parameters: [{}]16.12.2012 19:30:42 DEBUG (AbstractJob.java:278) - Job execution starting: JobExecution: id=2, version=0, startTime=null, endTime=null, lastUpdated=Sun Dec 16 19:30:42 GMT 2012, status=STARTING, exitStatus=exitCode=UNKNOWN;exitDescription=, job=[JobInstance: id=2, version=0, JobParameters=[{}], Job=[thirdJob]]16.12.2012 19:30:42 DEBUG (TransactionTemplate.java:159) - Initiating transaction rollback on application exception
org.springframework.batch.repeat.RepeatException: Exception in batch process; nested exception is java.lang.Exception: Unexpected Error!
...16.12.2012 19:30:43 DEBUG (BatchProcessStarter.java:51) - JobExecution: id=2, version=2, startTime=Sun Dec 16 19:30:42 GMT 2012, endTime=Sun Dec 16 19:30:43 GMT 2012, lastUpdated=Sun Dec 16 19:30:43 GMT 2012, status=FAILED, exitStatus=exitCode=FAILED;exitDescription=, job=[JobInstance: id=2, version=0, JobParameters=[{}], Job=[thirdJob]]

步骤22:下载
https://github.com/erenavsarogullari/OTV_SpringBatch_Chunk_Oriented_Processing

资源:

Spring Batch中的块处理

参考: Online Technology Vision博客中来自我们JCG合作伙伴 Eren Avsarogullari的Spring Batch中面向块的处理 。

翻译自: https://www.javacodegeeks.com/2012/12/chunk-oriented-processing-in-spring-batch.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

type=file文件上传H5新特性

1、语法 <input name"myFile" type"file"> 2、属性&#xff08;以下三个仅 HTML5支持&#xff0c;因此存在兼容性问题&#xff09;&#xff08;1&#xff09;multiple &#xff1a;表示用户是否可以选择多个值。multiple只能用于typefile和typeemail…

关于git的一些文章

为什么Github没有记录你的Contributions转载于:https://www.cnblogs.com/xiaobie123/p/7391266.html

epoll学习

一、epoll_create #include <sys/epoll.h>int epoll_create(int size); int epoll_create1(int flags); 返回&#xff1a;成功非负文件描述符&#xff0c;-1出错size:内核监听数目一共多大 创建一个epoll接口&#xff0c;size参数和select不同&#xff0c;不是fd1&#x…

为什么我不能关闭垃圾收集器?

首先让我们快速回顾一下我作为Java开发人员的职业生涯的早期。 我想消除正在进行的测试中的垃圾回收&#xff08;GC&#xff09;暂停。 瞧&#xff0c;当我发现无法完成时&#xff0c;我很生气。 那时&#xff0c;我将问题抛在了“设计错误”上&#xff0c;并继续前进。 对Jame…

background使用

background-position 有两个参数&#xff0c;定义背景图片起始位置可选值有&#xff1a; center top left right bottom px % background-size 可以用 px % 设定其宽高 值 cover 完全覆盖背景区域 contain 适应背景区域 background-origin 背景图片可以放置于 content-bo…

java牛客排序算法题_《剑指offer》面试题28:字符串的排列(牛客网版本) java...

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。输入描述: 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。这里尤其需要注意2点&#xff1a;1.所有组…

致第8年的自己

刚开始工作时&#xff0c;可能会用很多技术&#xff0c;知道很多技术就好像是很了不起的了。 但工作久了之后&#xff0c;如果还是只停留在知识的表面&#xff0c;技术只知个大概&#xff0c;那就显得太肤浅了。 别被人问倒&#xff0c;什么东西都能说出个一二&#xff0c;那才…

配置Ubuntu虚拟环境

配置Ubuntu虚拟环境 1.ubuntu默认root用户没有激活&#xff0c;激活root用户&#xff0c;就要为root用户创建密码$sudo passwd root2、修改主机名$vi /etc/hostname3、安装ssh服务$sudo apt-get install openssh-server//安装sshd服务$ sudo apt-get install openssh-server//开…

布局 — 样式重置

/* 清除默认内边距和外边距*/ body, dl, dd, h1, h2, h3, h4, h5, h6, p, form {margin: 0; } ol, ul {margin:0;padding:0; }/* 设置默认文字样式*/ html {font-size: calc((16 * 100vw) / 320);-webkit-text-size-adjust: none; } body, button, input, select, textarea {fo…

从Java执行可执行的命令行

在本文中&#xff0c;我们将介绍Java开发人员的常见需求。 从Java内部执行和管理外部流程。 由于这项任务很常见&#xff0c;因此我们着手寻找一个Java库来帮助我们完成它。 该库的要求是&#xff1a; 异步执行该过程。 能够中止流程执行。 等待流程完成的能力。 处理中的输…

java代码实现解压文件_Java压缩/解压文件的实现代码

用java压缩/解压文件&#xff1a;import java.io.*;import java.awt.*;import java.awt.event.*;import java.util.*;import java.util.zip.*;import javax.swing.*;//从压缩包中提取文件public class ZipExtractDemo extends JFrame{JFileChooser fileChooser; //文件选择器JT…

关于微信分享的一些心得之recommend.js(直接复制就行)

// import $ from jqueryimport Vue from vueexport default function (type,title,con,img,url,) { // 这里面的参数&#xff0c;你想怎么改就怎么改&#xff08;你自己也可以添加&#xff09;&#xff0c;类型&#xff0c;标题&#xff0c;内容&#xff0c;图片&#xff0c…

前端之bootstrap模态框

简介&#xff1a;模态框&#xff08;Modal&#xff09;是覆盖在父窗体上的子窗体。通常&#xff0c;目的是显示来自一个单独的源的内容&#xff0c;可以在不离开父窗体的情况下有一些互动。子窗体可提供信息、交互等。 Modal简介Modal实现弹出表单Modal实现删除提示框其他用法…

Python Excel操作——xlrd、xlwd

读取 1、导入模块 import xlrd 2、打开Excel文件读取数据 data xlrd.open_workbook(excel.xls) 3、获取一个工作表 1 table data.sheets()[0] #通过索引顺序获取 2 table data.sheet_by_index(0) #通过索引顺序获取 3 table data.sheet_by_name(uSheet1)#通过名…

js方式调用php_举例说明JS调用PHP和PHP调用JS的方法

举例说明JS调用PHP和PHP调用JS的方法在学习任何一门编程语言&#xff0c;我们都会听到调用这个词&#xff0c;那么&#xff0c;在javascript中是如何调用php的呢&#xff1f;在php中也可以调用js吗&#xff1f;下面就让我们一起来看看吧。1、JS方式调用PHP文件并取得PHP中的值举…

Java大新闻不断涌现:Java SE 6和OpenJDK

我最近公布的最新的Java 8新闻 &#xff0c;总结了一些最近的事态发展中的Java 8 。 自从发布该文章不到一周&#xff0c;就出现了更多重要的Java新闻报道&#xff0c;我在本文中总结了其中的一些内容。 共同的主题包括不同的Java SE 6实现和OpenJDK 。 Java安全性问题影响Ora…

如何在Hexo中实现自适应响应式相册功能

用最清晰简洁的方法整合一个响应式相册效果 技术选型 由于我选用的主题使用了fancyBox作为图片弹出展示的框架&#xff0c;查看后表示很不错&#xff0c;能满足需要http://fancyapps.com/fancybox/3/图片加载可能会太慢&#xff0c;所以还需要一个图片延迟加载插件 Lazyload想使…

vue css动画

.toggle-cart-enter-active, .toggle-cart-leave-active { transition: all .3s ease-out; } .toggle-cart-enter, .toggle-cart-leave-active { transform: translateY(100%); }

luinx php木马,Linux Bash Shell 寻找PHP(网站)挂马,后门

一php后门木马常用的函数大致上可分为四种类型&#xff1a;1. 执行系统命令: system, passthru, shell_exec, exec, popen, proc_open2. 代码执行与加密: eval, assert, call_user_func,base64_decode, gzinflate, gzuncompress, gzdecode, str_rot133. 文件包含与生成: requir…

关于类型安全的思考

这两天一初学python的哥们频频吐槽C#这样赋值时对类型的检查,让问题变难变复杂了. 解释几次类型检查的好处,效果不明显. 我也反思了一下, 类型检查真的是额外的包袱么?答案 是忠言逆耳利于行。 你是君王&#xff0c;语言是臣子,在君王犯错的时候: 一个臣子在事后说“你让我干的…