Search code examples
javaspringhibernatejpapersistence

JPA / Hibernate Out of Memory Exception


I've recently moved a project that was using native Hibernate entities and session management over to Spring, with annotation driven dependency injection and transaction management.

I have an Entity structure like this:

@Entity
@Table(name = "PARENT",uniqueConstraints=@UniqueConstraint(columnNames={"parentName"}))
public class Parent implements Serializable, {
    static final long serialVersionUID = 1L;

    @Id
    private int id;


    @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private Set<Child> child = new HashSet<Child>();
}



@Entity
@Table(name = "CHILD", uniqueConstraints = @UniqueConstraint(columnNames = {
        "childName", "parent_id" }))
@SequenceGenerator(name = "CHILD_SEQ", allocationSize = 1, sequenceName = "CHILD_SEQ")
public class Child implements Serializable {

    static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHILD_SEQ")
    private int id;
    private String childName = ""; //$NON-NLS-1$

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
}

Here's what happens.

  • I get all the parent objects which contain individual lists of child objects. This works quickly, I have the full object tree in memory in my debugger I can see every Child object is loaded correctly.

    public List<Parent> getParents() {
        return em.createQuery("from Parent",Parent.class).getResultList();
    }
    
  • I then try and get every Child object and the application freezes my PC slows down and after a few hours I get the Out on memory exception.

    public List<Child> getChildren() {
        return em.createQuery("from Child",Child.class).getResultList();
    }
    

I have looked at the generated SQL and for the first method it seems to logically break down the calls in to individual sets of objects and for the seconds it seems to construct a monster sized query that I can't really follow and that query doesn't appear to be returning, although I can't really tell.

What I cannot understand is why the query to the parent works so quickly and gives me every single object but the child query just breaks.


Solution

  • When you start with the parents Hibernate can read all parents (simple) and join with the child table (again, simple). Each child has exactly one parent, which is the one we join with, so that is enough. While the entire database is read into memory that is no problem as it is small.

    When you start with the children on the other hand Hibernate must first fetch the parent for each child. That means one join with the parent table. However, those parents have children, so we must join with the child table again in order to find them.

    Your classes are not complete, parent name is missing and you mention other collections. If the other collections are eager as well they would have to be fetched with joins for the first child level and the second child level as well, adding two more joins per collection. That makes for a very complex query!