spring batch

 http://www.4ucode.com/Study/Topic/478358

DelimitedLineTokenizer 的delimiter 默认是逗号','.names is as the fieldMap keys, it's not the header of feed file

FixedLengthTokenizer use the column index to split.

PassThroughFieldSetMapper just use the default filedSet. you can define your own field mapper.

 

 

Spring batch sample 之 text to DB
例子很简单:
txt文件如下:
   sampleSource.txt
     kinaei,30
     zoubin,40
     ZHUTOU,65
     wufeiran,51
 


需要存放到一张表中:
 
     CREATE MEMORY TABLE BATCH_TEST(NAME VARCHAR(20) NOT NULL PRIMARY KEY,AGE BIGINT)
  

  利用sts自带的spring-batch的模板生成样板代码。自己完成的无非是reader 和 writer两块。
  下面是主要的配置代码:
 
  <?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/batch http://www.springframework.org/schema/batch/spring-batch-2.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

	<description>Example job to get you started. It provides a
		skeleton for a typical batch application.</description>

	<job id="job1" xmlns="http://www.springframework.org/schema/batch">
		<step id="step1" parent="simpleStep">
			<tasklet>
				<chunk reader="reader" writer="writer"/>
			</tasklet>
		</step>
	</job>

<!--
	<bean id="reader" class="org.springframework.sample.batch.example.ExampleItemReader">
	   <property name="sampleFile" value="classpath:sampleSource.txt" />
	</bean>
-->
     <bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
         <property name="resource" value="classpath:sampleSource.txt" />
         <property name="lineMapper" >
                   <bean id="defaultLineMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                       <property name="lineTokenizer">
                           <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                              <property name="names">
                              <list>
                                 <value>name</value>
                                 <value>age</value>
                              </list>
                              </property>
                           </bean>
                       </property>
                       <property name="fieldSetMapper">
                       	   <bean  class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
	                             <property name="prototypeBeanName" value="testbean" />
	                       </bean>
                       </property>
                        
                   </bean>      
         </property>
     </bean>
    	
	<bean id="testbean" class="org.springframework.sample.batch.example.TestBean" scope="prototype"/>
     
     	
	<bean id="writer" class="org.springframework.sample.batch.example.ExampleItemWriter" >
        <property name="dataSource" ref="dataSource" />
    </bean>    
	<bean id="simpleStep"
		class="org.springframework.batch.core.step.item.SimpleStepFactoryBean"
		abstract="true">
		<property name="transactionManager" ref="transactionManager" />
		<property name="jobRepository" ref="jobRepository" />
		<property name="startLimit" value="100" />
		<property name="commitInterval" value="1" />
	</bean>
	

</beans>
  
 
 
主要的工作就是把需要读取的文件是一个逗号分割的文件,先把每一行转换为一个bean然后交给writer去写入数据库。
首先来看一下reader,Spring提供的基础设施及其完善,几乎不用写任何代码就能把一个reader配置完成了。一个reader主要由两部分组成:
    【1】resource 告诉reader从哪里去读文件
     
<property name="resource" value="classpath:sampleSource.txt" />

【2】lineMapper 就是说txt文件中的每一行映射成怎样的一个bean。
      如何把文件的一行映射成为一个bean呢?
  【A】需要知道分割符号式什么,在spring 中就叫做:lineTokenizer。可能的话还要提供每个字段对应的名称。
              
			                             <property name="lineTokenizer">
                           <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                              <property name="names">
                              <list>
                                 <value>name</value>
                                 <value>age</value>
                              </list>
                              </property>
                           </bean>
                       </property>
			   

   这里告诉系统用逗号分隔符,并且第一字段叫name,第二个字段叫age
          【B】需要把txt文件中的字段映射到bean中的对应字段中并且做好字段的类型转换工作。Spring中就叫做fieldSetMapper
               
				                          <property name="fieldSetMapper">
                       	   <bean  class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
	                             <property name="prototypeBeanName" value="testbean" />
	                       </bean>
                       </property>
				

      这里用到了spring的基础设施,即BeanWrapperFieldSetMapper它会根据txt文件读出的字段与给定的bean进行同名装配,自动的映射成了一个bean叫做testbean。
【C】 testbean 是什么的 定义如下
   
	   <bean id="testbean" class="org.springframework.sample.batch.example.TestBean" scope="prototype"/>
	   
	   package org.springframework.sample.batch.example;

import java.io.Serializable;

public class TestBean implements Serializable{
	private String name;
	private Integer age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}
	


这样reader就写好了。

剩下的就是writer了,由于spring没有提供方面的Database ItemWriters只能自己写了。
  
 package org.springframework.sample.batch.example;

import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ItemWriter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;


/**
 * Dummy {@link ItemWriter} which only logs data it receives.
 */
public class ExampleItemWriter implements ItemWriter<Object> {

	private static final Log log = LogFactory.getLog(ExampleItemWriter.class);
	
	private DataSource dataSource;
	
	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	/**
	 * @see ItemWriter#write(Object)
	 */
	public void write(List<? extends Object> data) throws Exception {
		TestBean rs=null;
		for(Object line : data){
			rs=(TestBean)line;  //actual just one
		}
		
		final Object[] params=new Object[2];
		params[0]=rs.getName();
		params[1]=rs.getAge();
		System.out.println(ToStringBuilder.reflectionToString(rs));
		
		
		TransactionTemplate transactionTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
		transactionTemplate.execute(new TransactionCallback() {
			public Object doInTransaction(TransactionStatus arg0) {
				JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
				jdbcTemplate.update("insert into BATCH_TEST(NAME,AGE) VALUES(?,?)",params);
				return null;
			}
		});
		
	}

}
  
   

  
   配置如下:
  
      	<bean id="writer" class="org.springframework.sample.batch.example.ExampleItemWriter" >
        <property name="dataSource" ref="dataSource" />
    </bean> 
   

  
   最后谈一下总体的感觉:
      【1】代码简单清晰许多,只需要把精力放在reader和writer的代码中。其他的如出错处理等都有spring代劳了。
【2】自动装配的这个reader用起来非常方便。
【3】自动实现了有状态的读取。为了防止读写过程中突然出错,在启动的时候重复读,或者漏读。以前读文件的时候要么是先把整个文件读写完毕后再commit,既浪费应用服务器的内存,又影响db的性能。要么要再写个文件记录读取的条数,重启后先判断读取的位置,在接着做。现在SPRING的这个reader自动提供了(当然代价是建立了记录状态的spring_batch的一系列的表),非常方便。
【4】在写writer的时候有spring来管理connection的事务提交。原来自己写的时候需要把connection传来传去以保证事务的完整性。比如如果要实现读两行再一次提交的话,可能connect 会贯穿于reader和writer或者再写个类去管理这个connection这里都提交给了spring。

实践下来我的结论是如果你要写一个读取文件,再做相应的处理后写入数据库的程序的话利用spring-batch绝对物有所值。

 

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值