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…

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…

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.所有组…

前端之bootstrap模态框

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

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

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

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

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

适用于MongoDB和Mongometer的SpiderMonkey至V8

通过10gen将MongoDB 2.3 / 2.4的默认JavaScript引擎从SpiderMonkey切换到V8&#xff0c;我想我将借此机会使用mongometer比较这些发行版的相对性能。 作为安全专家&#xff0c;我真的应该首先研究“ 其他身份验证功能” ……嘿。 我将记录比较过程中所采取的步骤&#xff08;包…

百度联盟广告如何理解按父容器宽度

创建百度联盟广告位的时候&#xff0c;选择按父容器宽度展示&#xff0c;但是在加入之后&#xff0c;查看代码发现广告的宽度为页面的宽度&#xff0c;并不是希望的父级的宽度&#xff0c; 如图在这里查看&#xff1a; 解析&#xff1a;百度联盟广告自动生成的div按父级的div宽…

php中文字转,PHP文字转图片功能原理与实现方法分析

本文实例讲述了PHP文字转图片功能。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这项功能主要用于对邮箱地址、手机等可能被网络爬虫抓取的重要信息的处理。将文字转化为图片绝对是个好注意。验证码的基本生成原理也与此差不多&#xff0c;只是对再对文字转化为图片的…

Java 系列之spring学习--spring搭建(一)

一、新建maven项目 二、引入spring jar包 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0…

php简单分页,php简单实现分页查询的方法

这篇文章主要为大家详细介绍了php简单实现分页查询的方法&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下关于php,最近学了好多&#xff0c;老师跟我们说&#xff0c;现在学的都是php的核心部分&#xff0c;所以我比较注意了一下&#xff0c;也多练习…

django用户认证系统——登录4

用户已经能够在我们的网站注册了&#xff0c;注册就是为了登录&#xff0c;接下来我们为用户提供登录功能。和注册不同的是&#xff0c;Django 已经为我们写好了登录功能的全部代码&#xff0c;我们不必像之前处理注册流程那样费劲了。只需几分钟的简单配置&#xff0c;就可为用…

web前端黑客技术揭秘 6.漏洞挖掘

6.1  普通XSS漏洞自动化挖掘思路 6.1.1  URL上的玄机 6.1.2  HTML中的玄机 2.HTML标签之内 6.1.3  请求中的玄机 6.1.4  关于存储型XSS挖掘 6.2.1  HTML与JavaScript自解码机制 <input type"button" id"exec_btn" value"exec" on…

Webpack基础使用

目录 一.什么是Webpack 二.为什么要使用Webpack 三.Webpack的使用 1.下载yarn包管理器 2.Webpack的安装 3.Webpack的简单使用 4.效果 四.Webpack打包流程 一.什么是Webpack Webpack是一个静态模块打包工具 二.为什么要使用Webpack 在开发中&#xff0c;我们常常会遇到…

阿帕奇骆驼遇见Redis

键值商店的兰博基尼 Camel是最好的面包集成框架&#xff0c;在本文中&#xff0c;我将向您展示如何通过利用另一个出色的项目Redis使它更加强大。 Camel 2.11即将发布&#xff0c;具有许多新功能&#xff0c;错误修复和组件。 这些新组件中的几个是我创作的&#xff0c; red…

HTML 教程- (HTML5 标准)摘抄笔记

HTML 教程- (HTML5 标准) 教程网址&#xff1a;http://www.runoob.com/html/html-tutorial.html http://blog.csdn.net/ljfbest/article/details/6700148 HTML版本 从初期的网络诞生后&#xff0c;已经出现了许多HTML版本: 版本发布时间HTML1991HTML 1993HTML 2.01995HTML 3…

Java EE CDI ConversationScoped示例

在本教程中&#xff0c;我们将向您展示如何在Web应用程序中创建和使用ConversationScoped Bean。 在CDI中&#xff0c;bean是定义应用程序状态和/或逻辑的上下文对象的源。 如果容器可以根据CDI规范中定义的生命周期上下文模型来管理其实例的生命周期&#xff0c;则Java EE组件…

Git 中文教程

以下内容转载自&#xff1a;http://www.open-open.com/lib/view/open1328928294702.html Git是一个分布式的版本控制工具&#xff0c;本篇文章从介绍Git开始&#xff0c;重点 在于介绍Git的基本命令和使用技巧&#xff0c;让你尝试使用Git的同时&#xff0c;体验到原来一个版本…

php markdown的转化函数,markdown公式转为知乎格式

在知乎中写技术类文章&#xff0c;经常会用到markdown知乎文章可以导入markdown格式&#xff0c;但是不支持Latex公式。知乎大神提供了替代方案&#xff1a; https://zhuanlan.zhihu.com/p/69142198为实现自动化&#xff0c;用python将其简易实现&#xff0c;代码如下&#xff…