【问题标题】:Spring Data JPA and loading large volumes of read-only data.Spring Data JPA 和加载大量只读数据。
【发布时间】:2018-09-29 02:10:38
【问题描述】:

我有一个包含 10M 行的 Person 表,并且该数据是只读的。我的应用程序在启动时通过 Spring Data JPA 将整个表读入一个 List,然后在应用程序的整个生命周期中使用这个 List,而无需进行任何 Person 查询。

我正在使用 Postgres 9.6、Java 8、Spring Data JPA 1.11 和 Hibernate 5.2,并且还有许多其他表更小/有更新等,总的来说一切都很好。

我遇到的问题是,我需要 2-3 倍的内存才能加载这 10M 个 Person 对象,而加载这些 Person 对象所需的内存是它们的。 在加载期间,JPA 将下载整个结果集,然后将其转换为我的 Person 对象,复制内存。 Hibernate 的一级缓存也持有这些对象。

Hibernate 有一个 StatelessSession 可以帮助我解决缓存问题 (https://gist.github.com/jelies/5181262),我可以一次执行 500k 行的分页查询或类似的操作,以便在加载时不复制整个数据集,但是有没有在 2018 年使用 Spring Data JPA 执行此操作的更简单方法?

即我可以一次将 Person 表流式传输到我的 Person 对象 N 行中,并在此过程中禁用所有缓存吗?

【问题讨论】:

  • 1.对于流式查询结果,请参阅herehereherehere 2.“Hibernate 的一级缓存也保留了这些对象”——这有什么关系?
  • 您的解决方案是什么?我正在尝试流式传输 200M 行,但进展并不顺利...
  • @JoshC。我使用了 StatelessSession - 这让我可以分批读取 500k。我用一些代码发布了答案。

标签: hibernate jpa spring-data-jpa jpa-2.1


【解决方案1】:

最终做了类似的事情。将获取大小设置为配置参数并测试不同的

    StatelessSession session = ((Session) em.getDelegate()).getSessionFactory().openStatelessSession();
    // wherever you want to store them
    List<MyObject> output = new ArrayList<>();
    ScrollableResults results = null;


    try {
        Query query = session.createQuery("SELECT a FROM MyObject a");
        query.setFetchSize(250_000);
        query.setReadOnly(true);
        query.setCacheable(false);
        query.setLockMode("a", LockMode.NONE);
        results = query.scroll(ScrollMode.FORWARD_ONLY);
        while (results.next()) {
            MyObject o = (MyObject) results.get(0);
            output.add(o);
        }
    }

【讨论】:

  • 我最终切换到 Spring Batch 并使用了 JDBC 游标。
猜你喜欢
  • 2012-06-01
  • 2018-03-01
  • 2015-04-04
  • 2018-09-17
  • 2022-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
相关资源
最近更新 更多