在spring批处理作业的读取器中实现键集分页

在spring批处理作业的读取器中实现键集分页,spring,pagination,spring-batch,Spring,Pagination,Spring Batch,我有一个spring批处理作业,它从Postgres数据库中获取数据,并在处理后将数据写入excel工作表。但我想在spring批处理作业的读取器中实现键集分页。目前,我使用的是使用限制偏移量分页的JpaPagingItemReader,但由于我处理大量数据,JpaPagingItemReader用于获取数据的查询会随着偏移量的增加而变得效率低下。键集分页可以用来避免限制偏移量分页的限制,但我不知道如何实现具有键集分页的读取器。我如何实现它 编辑: 键集分页不包括记录的偏移/跳过,相反,我们将对

我有一个spring批处理作业,它从Postgres数据库中获取数据,并在处理后将数据写入excel工作表。但我想在spring批处理作业的读取器中实现键集分页。目前,我使用的是使用限制偏移量分页的JpaPagingItemReader,但由于我处理大量数据,JpaPagingItemReader用于获取数据的查询会随着偏移量的增加而变得效率低下。键集分页可以用来避免限制偏移量分页的限制,但我不知道如何实现具有键集分页的读取器。我如何实现它

编辑: 键集分页不包括记录的偏移/跳过,相反,我们将对结果中的数字唯一标识符进行排序和跟踪,并请求大于最后一个唯一条目的条目。在这个方法中,SQL如下所示(假设customer_id是记录的唯一自动生成标识符)

在实现键集分页时,需要记住以下几点:

  • 每个记录都应该有一个数字唯一标识符( 最好是主键)
  • 结果集应该是有序的
  • 我们应该有逻辑来排序并在检索到的列表中找到最大的id
  • 您正在使用的标识符字段上应该有一个索引 偷看
  • 公共类CustomerProcessorService{
    公众客户(){
    列出客户=新建ArrayList();
    长lastCusId=0;
    int size=100;
    while(true){
    //创建一个PageRequest对象,该对象将作为可分页接口传递给repo
    //请注意,这里我们将0设置为偏移量
    PageRequest PageRequest=新的PageRequest(0,大小);
    //获取最后一个CUSID
    lastCusId=getLastCusId(客户);
    //从数据库中获取数据
    customers=customerRepository.findbystatus和customeridgreatertanorderbycustomeridasc('ACTIVE',lastCusId,pageRequest);
    //检查是否有数据
    if(customers==null | | customers.isEmpty()){
    打破
    }
    //处理
    } 
    }
    公共长getLastCusId(列出客户){
    //如果传递的条目为null或空,则返回0(这将处理第一个迭代案例)
    if(customers==null | | customers.isEmpty())
    返回0升;
    //按照每个客户的客户id对客户列表进行逻辑排序
    //客户对象
    //返回最后一个条目
    返回customers.get(customers.size()-1.getCustomerId();
    }
    
    您应该能够通过扩展
    AbstractPaginatedDataItemReader
    类来实现分页逻辑。这个基类处理大部分分页样板文件,并允许您在
    doPageRead
    中指定分页逻辑。下面是一个快速示例,我将让您相应地调整它:

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    import org.springframework.batch.item.data.AbstractPaginatedDataItemReader;
    import org.springframework.data.domain.PageRequest;
    
    public class KeySetPagingItemReader extends AbstractPaginatedDataItemReader<Customer> {
    
        long lastCusId = 0;
        int size = 100;
        private CustomerRepository customerRepository;
        List<Customer> customers = new ArrayList();
    
        public KeySetPagingItemReader(CustomerRepository customerRepository) {
            this.customerRepository = customerRepository;
        }
    
        @Override
        protected Iterator<Customer> doPageRead() {
            PageRequest pageRequest = PageRequest.of(0,size);
            // Get the lastCusId
            lastCusId = getLastCusId(customers);
            // Get the data from the database
            customers = customerRepository.findByStatusAndCustomerIdGreaterThanOrderByCustomerIdAsc('ACTIVE',lastCusId,pageRequest);
            return customers.iterator();
        }
    
        public Long getLastCusId(List<Customer> customers) {
            // If passed entry is null or empty, return 0 ( This handles the first iteration case )
            if ( customers == null || customers.isEmpty())
                return 0l;
    
            // Do the logic to sort the customers list by customer_id of each
            // Customer object
            // Return the last entry
            return customers.get(customers.size() -1).getCustomerId();
        }
    }
    
    import java.util.ArrayList;
    导入java.util.Iterator;
    导入java.util.List;
    导入org.springframework.batch.item.data.AbstractPaginatedDataItemReader;
    导入org.springframework.data.domain.PageRequest;
    公共类KeySetPagingItemReader扩展了AbstractPaginatedDataItemReader{
    长lastCusId=0;
    int size=100;
    私人客户存储客户存储;
    列出客户=新建ArrayList();
    public KeySetPagingItemReader(CustomerRepository CustomerRepository){
    this.customerRepository=customerRepository;
    }
    @凌驾
    受保护迭代器doPageRead(){
    PageRequest PageRequest=PageRequest.of(0,大小);
    //获取最后一个CUSID
    lastCusId=getLastCusId(客户);
    //从数据库中获取数据
    customers=customerRepository.findbystatus和customeridgreatertanorderbycustomeridasc('ACTIVE',lastCusId,pageRequest);
    return customers.iterator();
    }
    公共长getLastCusId(列出客户){
    //如果传递的条目为null或空,则返回0(这将处理第一个迭代案例)
    if(customers==null | | customers.isEmpty())
    返回0升;
    //按照每个客户的客户id对客户列表进行逻辑排序
    //客户对象
    //返回最后一个条目
    返回customers.get(customers.size()-1.getCustomerId();
    }
    }
    
    你能解释什么是键集分页吗?没有Spring Batch,你会怎么做?如果你分享你的代码,我可以帮助你用它创建一个Spring批处理读取器。@MahmoudBenHassine我添加了一个简短的解释以及实现键集分页的伪代码。我们如何在Spring批处理读取器中使用它?好的,谢谢你的更新。我添加了一个答案,其中包含一个需要编译/改编的示例。希望能有所帮助。@MahmoudBenHassine感谢您的答案。我还有一个疑问,如果lastCusId是UUID,则lastCusId的初始值应该是多少如果您的customerId是UUID,则说明中的第1点和第2点不再有效,并且此“键集分页”该技术将不再有效。您需要找到另一个标准来对数据进行排序/分页。我们是否也可以在此处使用AbstractPagingItemReader?AbstractPagingDataItemReader和AbstractPagingItemReader之间的区别是什么?是的,您可以。它们确实很相似,但在处理分页的方式上有细微的区别。AbstractPaginatedDataItemReader是按照Spring数据处理分页的方式设计的。
    public class CustomerProcessorService {
        public void processCustomers() {
            List<Customer> customers = new ArrayList();
            long lastCusId = 0;
            int size = 100;
            while ( true ) {
                // Create a PageRequest object that will be passed as Pageable interface to repo
                // Note that here we are setting 0 as the offset
                PageRequest pageRequest = new PageRequest(0,size);
                // Get the lastCusId 
                lastCusId = getLastCusId(customers);
                // Get the data from the database
                customers = customerRepository.findByStatusAndCustomerIdGreaterThanOrderByCustomerIdAsc('ACTIVE',lastCusId,pageRequest);
                // Check if data is there
                if ( customers == null || customers.isEmpty()) {
                    break;
                }
                // Do the processing
            } 
        }
        public Long getLastCusId(List<Customer> customers) {
            // If passed entry is null or empty, return 0 ( This handles the first iteration case ) 
            if ( customers == null || customers.isEmpty()) 
                return 0l;
            
            // Do the logic to sort the customers list by customer_id of each
            // Customer object
            // Return the last entry 
            return customers.get(customers.size() -1).getCustomerId();
        }
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    import org.springframework.batch.item.data.AbstractPaginatedDataItemReader;
    import org.springframework.data.domain.PageRequest;
    
    public class KeySetPagingItemReader extends AbstractPaginatedDataItemReader<Customer> {
    
        long lastCusId = 0;
        int size = 100;
        private CustomerRepository customerRepository;
        List<Customer> customers = new ArrayList();
    
        public KeySetPagingItemReader(CustomerRepository customerRepository) {
            this.customerRepository = customerRepository;
        }
    
        @Override
        protected Iterator<Customer> doPageRead() {
            PageRequest pageRequest = PageRequest.of(0,size);
            // Get the lastCusId
            lastCusId = getLastCusId(customers);
            // Get the data from the database
            customers = customerRepository.findByStatusAndCustomerIdGreaterThanOrderByCustomerIdAsc('ACTIVE',lastCusId,pageRequest);
            return customers.iterator();
        }
    
        public Long getLastCusId(List<Customer> customers) {
            // If passed entry is null or empty, return 0 ( This handles the first iteration case )
            if ( customers == null || customers.isEmpty())
                return 0l;
    
            // Do the logic to sort the customers list by customer_id of each
            // Customer object
            // Return the last entry
            return customers.get(customers.size() -1).getCustomerId();
        }
    }