Spring Batch:聚合记录和写入计数

时间:2015-11-20 11:24:36

标签: spring spring-batch

我们在平面文件中有一些数据。 e.g。

EmpCode,Salary,EmpName,...  
100,1000,...,...
200,2000,...,...
200,2000,...,...
100,1000,...,...
300,3000,...,...
400,4000,...,...

我们希望根据EmpCode汇总薪水,并将数据写为

Emp_Code    Emp_Salary   Updated_Time   Updated_User 
100         2000         ...            ...
200         4000         ...            ...
300         3000         ...            ...
400         4000         ...            ...

我按照Spring Batch编写了类,如下所示

ItemReader - to read the employee data into a Employee object                

示例EmployeeItemProcessor:

public class EmployeeProcessor implements ItemProcessor<Employee, Employee> {

    @Override
    public Employee process(Employee employee) throws Exception {
        employee.setUpdatedTime(new Date());
        employee.setUpdatedUser("someuser");
        return employee;
    }

EmployeeItemWriter:

@Repository
public class EmployeeItemWriter implements ItemWriter<Employee> { 
 @Autowired
 private SessionFactory sf;

 @Override  
 public void write(List<? extends Employee> employeeList) throws Exception {  
  List<Employee> aggEmployeeList = aggregateEmpData(employeeList);
  //write to db using session factory
 }  

 private List<Employee> aggregateEmpData(List<? extends Employee> employeeList){
     Map<String, Employee> map = new HashMap<String, Employee>(); 
    for(Employee e: employeeList){
        String empCode =  e.getEmpCode();
        if(map.containsKey(empCode)){
            //get employee salary and add up
         }else{
          map.put(empCode,Employee);
         }
     }    
     return new ArrayList<Employee>(map.values());         
 }
}

XML配置

...
<batch:job id="employeeJob">
    <batch:step id="step1">
    <batch:tasklet>
        <batch:chunk reader="employeeItemReader" 
            writer="employeeItemWriter" processor="employeeItemProcessor"
            commit-interval="100">
        </batch:chunk>
    </batch:tasklet>
    </batch:step>
  </batch:job>
...

它正在发挥作用并服务于我的目的。但是,我有几个问题。

1)当我查看日志时,它显示如下(commit-interval = 100):

status = COMPLETED,exitStatus = COMPLETED,readCount = 2652,filterCount = 0, writeCount = 2652 readSkipCount = 0,writeSkipCount = 0,processSkipCount = 0,commitCount = 27,rollbackCount = 0

但是在聚合之后,只有2515条记录被写入数据库。写入次数为2652.是否因为到达ItemWriter的项目数仍为2652?如何纠正?

2)我们两次遍历列表。一次在ItemProcessor中,然后在ItemWriter中进行聚合。如果记录数量更高,则可能是性能问题。有没有更好的方法来实现这个目标?

3 个答案:

答案 0 :(得分:2)

如果输入文件的每一行都是一个雇员对象,那么 ReadCount 将是输入文件中的行数。 WriteCount 将是传递给项目编写者的所有列表的大小的总和。因此,也许您的 aggregateEmpData 函数会将某些记录删除或聚合为一个,因此您的数据库计数与 WriteCount 不同。 如果要确保 WriteCount 与db中的记录数完全相同,则应在处理器中进行聚合。

答案 1 :(得分:1)

我设法写了。我这样做了。

public class EmployeeProcessor implements ItemProcessor<Employee, Employee> {
    Map<String, Employee> map;
    @Override
    public Employee process(Employee employee) throws Exception {
        employee.setUpdatedTime(new Date());
        employee.setUpdatedUser("someuser");
        String empCode =  employee.getEmpCode();
        if(map.containsKey(empCode)){
            //get employee salary and add up
            return null; 
         }
         map.put(empCode,employee);
         return employee;
    }

    @BeforeStep
    public void beforeStep(StepExecution stepExecution) {
         map = new HashMap<String, Employee>(); 
    }

写入计数现在正确显示。

答案 2 :(得分:0)

为什么ItemWriter中的汇总?我会在ItemProcessor中完成。这将允许写入计数准确并将该组件与实际写入行为分开。如果您对配置有所了解,我们可以详细说明。