2017-09-20 52 views
1

我使用Spring Boot 1.5.7和Spring Data JPA和Spring Batch。我使用JpaPagingItemReader<T>来读取实体,并使用JpaItemWriter<T>来写入它们。我想要做的是从某个数据库表中读取数据,将它们转换为不同的格式并将它们写回不同的表格(我读取原始json字符串,将它们反序列化并将它们插入到它们的特定表格中)。Spring批量查询状态变化

我不打算删除处理它们后读取的数据,而只是想将它们标记为已处理。现在的问题是,将JpaPagingItemReader手柄读起来很好,如果我作出这样的查询到的东西:

@Bean 
    public ItemReader<RdJsonStore> reader(){ 
     JpaPagingItemReader<RdJsonStore> reader = new JpaPagingItemReader<>(); 
     reader.setEntityManagerFactory(entityManagerFactory); 
     reader.setQueryString("select e from RdJsonStore e "+ 
           "where e.jsonStoreProcessedPointer is null"); 
     reader.setPageSize(rawDataProperties.getBatchProcessingSize()); 
     return reader; 
    } 

所以,如果没有指针,它会只读。我会在处理一个条目之后插入一个指针(批量处理,如我处理1000条目并将其所有ID发布到指针表)。

如果我更改为像这样运行时返回的数据(它尝试查询的条目每批减少),ItemWriter(和JPA one)是否可以处理读取的数据?

如果指针解决方案不适用,我应该如何设计DB-to-DB批处理作业?

我的源表看起来像这样:

enter image description here

+0

不,它不能,基础数据发生变化,并且对于每个页面查询重新执行,您将开始丢失数据。 –

+0

@ M.Deinum这是我想到的:( – appl3r

回答

0

如果你看看JpaPagingItemReader的代码,方法doReadPage(),你会发现这条线,

Query query = createQuery().setFirstResult(getPage() * getPageSize()).setMaxResults(getPageSize());

其中createQuery()是,

private Query createQuery() { 
     if (queryProvider == null) { 
      return entityManager.createQuery(queryString); 
     } 
     else { 
      return queryProvider.createQuery(); 
     } 
    } 

因此,您会发现每个页面都会重新创建/执行查询,但页码不会根据新数据集重新计算,并且页码重新计算也没有意义。

getPageSize()总是返回值在配置和getPage()回报设定最后计算的页面数(前面处理的页面+ 1),所以如果数据正在萎缩,你的程序将正常工作,如果页面数计算也做了重新即你总是页开始= 0,并且JpaPagingItemReader不会发生这种情况,所以您将会丢失M Deinum在注释中指定的数据。

另外,按我的理解,新数据的添加将工作OK(提供了新的记录被添加在末尾按排序即使作业运行过程中的数据的锁定通常假定键)。

我认为,目前的工作运行过程中标记一行作为PROCESSED没有任何意义,因为已经由框架照顾(作为一个记录是没有得到处理两次)。

什么,你可能需要的是标志着一个纪录下一个作业中处理运行并且可以通过更新一个独立的标志,它是不是WHERE条款部分(作业运行期间)以结束处理,然后工作 - 更新WHERE子句(您在WHERE子句中用于指示有关处理的记录)的一部分的标志。

+0

我想标记它们,因为我的工作将由用户手动启动。如果他们再次启动Job以获得相同的资源,他们可能会复制数据,但我决定在我写作时处理这个问题,而不是当我读时。 – appl3r