Jpa 阅读器 Spring Batch

0 java spring jpa spring-batch

我想知道,是否建议使用这种方式来使用 jpa 实现读者 spring 批处理,或者是否最好寻找另一种解决方案,如果不建议使用这种方式,我在哪里可以找到有关更好选项的信息

public class CreditCardItemReader implements ItemReader<CreditCard> {

@Autowired
private CreditCardRepository respository;

private Iterator<CreditCard> usersIterator;

@BeforeStep
public void before(StepExecution stepExecution) {
    usersIterator = respository.someQuery().iterator();
}

@Override
public CreditCard read() {
    if (usersIterator != null && usersIterator.hasNext()) {
        return usersIterator.next();
    } else {
        return null;
    }
}
  }
Run Code Online (Sandbox Code Playgroud)

Eug*_*ene 5

这种实现仅适用于小数据集,因为数据是通过一批查询读取的,并将整个结果列表存储在内存中。而且,它不是线程安全的。\n
在加载大量数据的情况下:

\n
    \n
  • 在内存有限的环境下可能会导致内存不足
  • \n
  • 可能会导致性能问题。我们将等到一次调用从数据库加载数千条记录
  • \n
\n


解决方案 1,org.springframework.batch.item.database.JpaCursorItemReader \n
Spring Batch 中开箱即用定义了类似的实现:JpaCursorItemReader\n
主要区别在于,此实现仅适用于特定的 JPQL 查询,而不是存储库和使用JPA\xe2\x80\x99s Query.getResultStream()方法来获取查询结果。\n
的实现JpaCursorItemReader

\n
    protected void doOpen() throws Exception {\n        ...\n        Query query = createQuery();\n        if (this.parameterValues != null) {\n            this.parameterValues.forEach(query::setParameter);\n        }\n        this.iterator = query.getResultStream().iterator();\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

例如,HibernateQuery.getResultStream()在 5.2 版本中引入了该方法。\n它使用 Hibernate\xe2\x80\x99sScrollableResult实现来移动结果集并批量获取记录。这可以防止您一次加载结果集的所有记录,并允许您更有效地处理它们。\n
创建示例:

\n
    protected ItemReader<Foo> getItemReader() throws Exception {\n        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();\n        String jpqlQuery = "from Foo";\n        JpaCursorItemReader<Foo> itemReader = new JpaCursorItemReader<>();\n        itemReader.setQueryString(jpqlQuery);\n        itemReader.setEntityManagerFactory(factoryBean.getObject());\n        itemReader.afterPropertiesSet();\n        itemReader.setSaveState(true);\n        return itemReader;\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

解决方案2,org.springframework.batch.item.database.JpaPagingItemReader \n
这是比JPQL查询更灵活的解决方案JpaCursorItemReader。ItemReader 按页加载和存储数据,并且它是线程安全的。\n
根据文档:

\n
\n

ItemReader 用于读取构建在 JPA 之上的数据库记录。

\n

它执行 JPQL setQueryString(String) 来检索请求的\n数据。使用 AbstractPagingItemReader.setPageSize(int) 中指定大小的分页请求来执行查询。当需要时,\n当调用 AbstractItemCountingItemStreamItemReader.read() 方法时,\n会请求其他页面,\n返回与当前位置相对应的对象。

\n

分页的性能取决于 JPA 实现和\n使用数据库特定功能来限制返回行数的情况。

\n

设置相当大的页面大小并使用与页面大小匹配的提交间隔\n应该可以提供更好的性能。

\n

为了减少大型结果的内存使用,在读取每个页面后,将刷新并清除持久性\n上下文。这会导致读取的任何实体\n被分离。如果您对实体进行更改\n并且希望保留更改,则必须显式合并\n实体。

\n

该实现在调用之间是线程安全的

\n
\n

解决方案3,org.springframework.batch.item.data.RepositoryItemReader \n
这是一个更高效的解决方案。它与存储库配合使用,以块的形式加载和存储数据,并且它是线程安全的。\n
根据文档:

\n
\n

使用 PagingAndSortingRepository 读取记录的 ItemReader。\n

\n

读取器的性能取决于存储库的实现,但是设置相当大的页面大小并将其与提交间隔匹配应该会产生更好的性能。

\n

读取器必须配置 PagingAndSortingRepository、\nSort 和大于 0 的 pageSize。

\n

此实现在对\nAbstractItemCountingItemStreamItemReader.open(ExecutionContext) 的调用之间是线程安全的,但\n如果在多线程客户端中使用,\n请记住使用 saveState=false(无法重新启动)。

\n
\n

创建示例:

\n
PagingAndSortingRepository<Foo, Long> repository = FooRepository<>();\nRepositoryItemReader<Foo> reader = new RepositoryItemReader<>();\nreader.setRepository(repository ); //The PagingAndSortingRepository implementation used to read input from.\nreader.setMethodName("findByName"); //Specifies what method on the repository to call.\nreader.setArguments(arguments); // Arguments to be passed to the data providing method.\n
Run Code Online (Sandbox Code Playgroud)\n

通过构建器创建:

\n
PagingAndSortingRepository<Foo, Long> repository = new FooRepository<>();\nnew RepositoryItemReaderBuilder<>().repository(repository)\n                                   .methodName("findByName")\n                                   .arguments(new ArrayList<>())\n                                   .build()\n
Run Code Online (Sandbox Code Playgroud)\n

更多使用示例:RepositoryItemReaderTestsRepositoryItemReaderIntegrationTests

\n

总结: \n
您的实现仅适用于简单的用例。\n
我建议使用开箱即用的解决方案。

\n