我想知道,是否建议使用这种方法来实现带jpa的reader 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;
    }
}
  }

推荐答案

这种实现只适用于小数据集,因为数据通过一次批处理查询读取,并将整个结果列表存储在内存中.而且,它不是线程安全的.

  • 在内存有限的环境中可能会导致内存不足
  • 可能会导致性能问题.我们将等待,直到通过一次调用从DB加载数千条记录


Solution 1, 100

    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()方法.

    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;
    }

Solution 2, 100

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

它执行JPQL setQueryString(字符串)以检索请求的

分页的性能取决于JPA实现和

设置相当大的页面大小并使用提交间隔

为了减少大结果的内存使用,持久性

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

Solution 3, 100

一种项目阅读器,利用

读卡器的性能取决于存储库

必须为读卡器配置分页和排序存储库

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

创建示例:

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()

更多用法示例:RepositoryItemReaderTestsRepositoryItemReaderIntegrationTests

Summarise:

Java相关问答推荐

使用 Java 流对嵌套对象进行分组和排序

调用方法以try 并重新运行代码块

按当前月份排序 List 到最近六个月

如何在不定义每个 Spring bean 的情况下创建多个相同类型的 Spring bean

将 4 个已排序的数组合并为一个

使用状态模式了解对象的状态

JVM字节码中的“dup2_x2”指令有什么用?

Do...while 在输入验证中不起作用

英特尔酷睿 i5 处理器上的 Java 多线程

Java 使用多个类型参数初始化数组错误 java.lang.ClassCastException: [Ljava.lang.Object;不能转换为

Java 并发:需要同时进行 2 个 Web 服务调用 - 这是正确的吗?

为什么 Intellij 想法会在 if 条件下警告空指针?

EntityManager.remove 和 EntityManager.persist 上的 JPA 重复条目错误

如何为 JDK 17 编写 Github 工作流

BufferedReader 没有读取整个字符串

FileInputStream 真的没有缓冲吗?

Java - 单个语句中的变量声明、赋值和空值判断

Android - 中止崩溃

无法解析方法“assertThat(int)”

我们如何定义一个带有填充的列,并且只有一个项目不继承 Jetpack Compose 中列的填充?