I am trying to refactor some JPA code and make it more readable by using javax.persistence.TypedQuery#getResultStream
(source code: https://github.com/behrangsa/hibernate-get-result-stream).
I thought returning a Stream
instead of a List
will prevent loading the entire data set into memory and will have a lower memory footprint. However in my tests I am getting OutOfMemoryError
:
persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="hibstr">
<description>Hibernate EntityManager Demo</description>
<class>org.behrang.misc.hibstr.Post</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL95Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost:32768/benchmark?currentSchema=benchmark"/>
<property name="javax.persistence.jdbc.user" value="postgres"/>
<property name="javax.persistence.jdbc.password" value="password"/>
</properties>
</persistence-unit>
</persistence>
PostTest
package org.behrang.misc.hibstr;
import org.hibernate.jpa.QueryHints;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import java.util.stream.Stream;
public class PostTest {
private static EntityManagerFactory entityManagerFactory;
@BeforeClass
public static void setup() {
entityManagerFactory = Persistence.createEntityManagerFactory("hibstr");
}
@AfterClass
public static void teardown() {
if (entityManagerFactory.isOpen()) {
entityManagerFactory.close();
}
}
@Test
public void shouldNotThrowOutOfMemoryError() {
final EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
final TypedQuery<Post> query = entityManager.createQuery("SELECT p from Post p", Post.class);
query.setHint(QueryHints.HINT_FETCH_SIZE, 25);
query.setHint(QueryHints.HINT_READONLY, "true");
try (final Stream<Post> posts = query.getResultStream()) {
posts.forEach(p -> {
System.out.println(p.getId());
});
}
entityManager.getTransaction().commit();
entityManager.close();
}
}
This outputs:
1
2
3
...
6362
Java heap space
java.lang.OutOfMemoryError: Java heap space
Any ideas what am I missing here?
EDIT: MySQL also causes OOM
See: https://github.com/behrangsa/hibernate-get-result-stream/tree/mysql