我想知道,这种方式是否推荐用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;
}
}
}发布于 2022-05-13 21:18:59
此实现仅适用于小型数据集,因为数据由一个批处理查询读取,并将整个结果列表存储在内存中。而且,它也不是线程安全的。
在装载大量卷的情况下:
解决方案1, org.springframework.batch.item.database.JpaCursorItemReader
在Spring中有一个类似的实现是开箱即用的:JpaCursorItemReader
主要区别在于,该实现仅用于特定的JPQL查询,而不是存储库,并使用JPA的Query.getResultStream()方法获取查询结果。
JpaCursorItemReader的实现
protected void doOpen() throws Exception {
...
Query query = createQuery();
if (this.parameterValues != null) {
this.parameterValues.forEach(query::setParameter);
}
this.iterator = query.getResultStream().iterator();
}例如,Hibernate在版本5.2中引入了Query.getResultStream()方法。它使用Hibernate的ScrollableResult实现来遍历结果集并分批获取记录。这将阻止您一次加载结果集的所有记录,并允许您更有效地处理这些记录。
创造的例子:
protected ItemReader<Foo> getItemReader() throws Exception {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
String jpqlQuery = "from Foo";
JpaCursorItemReader<Foo> itemReader = new JpaCursorItemReader<>();
itemReader.setQueryString(jpqlQuery);
itemReader.setEntityManagerFactory(factoryBean.getObject());
itemReader.afterPropertiesSet();
itemReader.setSaveState(true);
return itemReader;
}解决方案2, org.springframework.batch.item.database.JpaPagingItemReader
它比JpaCursorItemReader更灵活地解决JPQL查询问题。ItemReader通过页面加载和存储数据,并且它是线程安全的.
根据文件:
用于读取建立在JPA之上的数据库记录的ItemReader。 它执行JPQL setQueryString(String)来检索请求的数据。查询使用AbstractPagingItemReader.setPageSize(int)中指定大小的分页请求执行。在调用AbstractItemCountingItemStreamItemReader.read()方法时,当需要时会请求其他页面,返回与当前位置对应的对象。 分页的性能取决于JPA实现及其使用特定于数据库的特性来限制返回的行数。 设置相当大的页面大小并使用与页面大小匹配的提交间隔应该会提供更好的性能。 为了减少大型结果的内存使用量,在读取每个页面之后,将刷新和清除持久性上下文。这将导致任何读取的实体被分离。如果您对实体进行更改并希望这些更改保持不变,则必须显式合并这些实体。 在调用之间,实现是线程安全的。
解决方案3, org.springframework.batch.item.data.RepositoryItemReader
这是一个更有效的解决方案。它与存储库一起工作,以块加载和存储数据,并且是线程安全的。
根据文件:
使用ItemReader读取记录的PagingAndSortingRepository。 读取器的性能取决于存储库实现,但是,设置相当大的页面大小并将其与提交间隔匹配应该会产生更好的性能。 读取器必须配置为PagingAndSortingRepository、排序和大于0的pageSize。 这个实现在对AbstractItemCountingItemStreamItemReader.open(ExecutionContext),的调用之间是线程安全的,但是如果在多线程客户机中使用的话,请记住使用saveState=false (没有重新启动可用)。
创造的例子:
PagingAndSortingRepository<Foo, Long> repository = FooRepository<>();
RepositoryItemReader<Foo> reader = new RepositoryItemReader<>();
reader.setRepository(repository ); //The PagingAndSortingRepository implementation used to read input from.
reader.setMethodName("findByName"); //Specifies what method on the repository to call.
reader.setArguments(arguments); // Arguments to be passed to the data providing method.通过建造者创作:
PagingAndSortingRepository<Foo, Long> repository = new FooRepository<>();
new RepositoryItemReaderBuilder<>().repository(repository)
.methodName("findByName")
.arguments(new ArrayList<>())
.build()更多用法示例:RepositoryItemReaderTests和RepositoryItemReaderIntegrationTests
摘要:
您的实现仅适用于简单的用例。
我建议使用开箱即用的解决方案。
https://stackoverflow.com/questions/72233018
复制相似问题