spring batch

SpringBatch是解决企业数据逻辑较简单,重复性高,大数据量而设计的.从他提供的各种Reader就能看出来.起码我是这样理解的.最适合做的如:数据清洗,数据分析后转移,或者定时的和其他系统交互的地方等.

在上一篇文章中,我使用了 JdbcPagingItemReader读取HSQLDB数据库的数据.

01<bean id="sysAppStoreMapper" class="net.dbatch.mapper.SysAppStoreMapper" />
02  
03<bean id="dbReader"
04          class="org.springframework.batch.item.database.JdbcPagingItemReader">
05        <property name="dataSource" ref="dataSource"/>
06        <property name="rowMapper" ref="sysAppStoreMapper"/>
07        <property name="queryProvider" ref="appQueryProvider"/>
08    </bean>
09  
10  
11    <bean id="appQueryProvider"
12          class="org.springframework.batch.item.database.support.HsqlPagingQueryProvider">
13        <property name="selectClause" value="a.APP_ID, a.PARENT_ID, a.APP_DESC, a.APP_URL, a.FOLDER, a.SEQ"/>
14        <property name="fromClause" value="sys_appstore a"/>
15        <property name="sortKey" value="SEQ"/>
16    </bean>

事实上SpringBatch提供了很多的Reader,自定义的Reader只要是继承自org.springframework.batch.item.ItemReader接口的都可以.但是好多都不用你麻烦了,SpringBatch都替你做好了.2.1.8API中基本常用的和数据库[Hibernate/Ibatis/JDBC],文件系统,JMS消息等Reader现成的实现.如图:

 


对于喜欢SpringJDBC的用户[我就非常不喜欢Hibernate ]可以使用JdbcPagingItemReader

,然后指定一个queryProvider ,queryProvider 是针对各种数据库的一个分页的实现,常用的数据库 queryProvider也有现成的.如图:



好了.如果上面你实在找不到你可以使用的数据库对应的实现,而你又了解你的数据库SQL,你可以使用JdbcCursorItemReader.这个Reader允许你自己set SQL.

如我上面实现的例子,用JdbcCursorItemReader改写也非常简单:

1<bean id="dbReader"
2          class="org.springframework.batch.item.database.JdbcCursorItemReader">
3        <property name="dataSource" ref="dataSource" />
4        <property name="sql" value="select a.APP_ID, a.PARENT_ID, a.APP_DESC, a.APP_URL, a.FOLDER from sys_appstore a order by a.SEQ"/>
5        <property name="rowMapper" ref="sysAppStoreMapper" />
6    </bean>

他仍然可以工作的很好,而且还简单了.

如果我的数据来源不是从数据库,从文件的怎么办

看到刚才的Reader实现里有个FlatFileItemReader没他就是读取文件[文本文件]的.

假如我要分析这样结构的log日志信息

01User1,20
02User2,21
03User3,22
04User4,23
05User5,24
06User6,25
07User7,26
08User8,27
09User9,28
10User10,29

他都是一些结构化的文本文件,我可以很容易的实现.如Spring代码:

01<bean id="delimitedLineTokenizer" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer" />
02  
03    <bean id="lineMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
04        <property name="lineTokenizer" ref="delimitedLineTokenizer" />
05        <property name="fieldSetMapper">
06            <bean class="net.dbatch.sample.UserMapper" />
07        </property>
08    </bean>
09  
10    <bean id="messageReader" class="org.springframework.batch.item.file.FlatFileItemReader">
11        <property name="lineMapper" ref="lineMapper" />
12        <property name="resource" value="classpath:/users.txt" />
13    </bean>

再写上一个对应的Bean

01public class UserMapper implements FieldSetMapper<User> {
02      
03      
04    public User mapFieldSet(FieldSet fs) throws BindException {
05        User u = new User();
06        u.setName(fs.readString(0));
07        u.setAge(fs.readInt(1));
08        return u;
09    }
10}

Processor:

01public class MessagesItemProcessor implements ItemProcessor<User, Message> {
02  
03    public Message process(User user) throws Exception {
04        if(!StringUtils.hasText(user.getName())){
05            throw new RuntimeException("The user name is required!");
06        }
07        Message m = new Message();//Message是user一个简单的包装
08        m.setUser(user);
09        m.setContent("Hello " + user.getName()
10                ",please pay promptly at end of this month.");
11        return m;
12    }
13}

Writer:

1public class MessagesItemWriter implements ItemWriter<Message> {
2  
3    public void write(List<? extends Message> messages) throws Exception {
4        System.out.println("write results");
5        for (Message m : messages) {
6            System.out.println(m.getContent());  //只做输出
7        }
8    }
9}

测试代码:

01public static void main(String[] args) {
02        ClassPathXmlApplicationContext c = new ClassPathXmlApplicationContext("localfile_job.xml");
03        SimpleJobLauncher launcher = new SimpleJobLauncher();
04        launcher.setJobRepository((JobRepository) c.getBean("jobRepository"));
05        launcher.setTaskExecutor(new SyncTaskExecutor());
06        try {
07            JobExecution je = launcher.run((Job) c.getBean("messageJob"),
08                    new JobParametersBuilder().toJobParameters());
09            System.out.println(je);
10            System.out.println(je.getJobInstance());
11            System.out.println(je.getStepExecutions());
12        catch (Exception e) {
13            e.printStackTrace();
14        }
15    }

输出:

0110-20 15:28:32 INFO [job.SimpleStepHandler] - <Executing step: [messageStep]>
02write results
03Hello User1,please pay promptly at end of this month.
04Hello User2,please pay promptly at end of this month.
05Hello User3,please pay promptly at end of this month.
06Hello User4,please pay promptly at end of this month.
07Hello User5,please pay promptly at end of this month.
08write results
09Hello User6,please pay promptly at end of this month.
10Hello User7,please pay promptly at end of this month.
11Hello User8,please pay promptly at end of this month.
12Hello User9,please pay promptly at end of this month.
13Hello User10,please pay promptly at end of this month.
1410-20 15:28:32 INFO [support.SimpleJobLauncher] - <Job: [FlowJob: [name=messageJob]] completed with the following parameters: [{run.month=2011-10}] and the following status: [COMPLETED]>
15JobExecution: id=0, version=2, startTime=Sat Oct 20 15:28:32 CST 2012, endTime=Sat Oct 20 15:28:32 CST 2012, lastUpdated=Sat Oct 20 15:28:32 CST 2012, status=COMPLETED, exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=0, version=0, JobParameters=[{run.month=2011-10}], Job=[messageJob]]
16JobInstance: id=0, version=0, JobParameters=[{run.month=2011-10}], Job=[messageJob]
17[StepExecution: id=1, version=5, name=messageStep, status=COMPLETED, exitStatus=COMPLETED, readCount=10, filterCount=0, writeCount=10 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=3, rollbackCount=0, exitDescription=]

从日志里,我们可以清楚的看到.他是每行的读取并送入Processor中处理,完成5次读取进行一次性的写入.tasklet的属性 commit-interval可以调节此值.

全部的Spring配置:

01<batch:job id="messageJob" restartable="true">
02        <batch:step id="messageStep">
03            <batch:tasklet>
04                <batch:chunk reader="messageReader" 
05                processor="messageProcessor" 
06                writer="messageWriter"
07                commit-interval="5" 
08                chunk-completion-policy="" 
09                retry-limit="2">
10                    <batch:retryable-exception-classes>
11                        <batch:include class="java.lang.RuntimeException" />
12                    </batch:retryable-exception-classes>
13                </batch:chunk>
14            </batch:tasklet>
15        </batch:step>
16    </batch:job>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值