Recientemente moví un proyecto que usaba entidades nativas de Hibernate y administración de sesiones a Spring, con administración de transacciones e inyección de dependencia impulsada por anotaciones.
Tengo una estructura de entidad como esta:
@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; }Esto es lo que sucede.
Obtengo todos los objetos principales que contienen listas individuales de objetos secundarios. Esto funciona rápidamente, tengo el árbol de objetos completo en la memoria de mi depurador. Puedo ver que cada objeto secundario se carga correctamente.
public List<Parent> getParents() { return em.createQuery("from Parent",Parent.class).getResultList(); }Luego trato de obtener todos los objetos secundarios y la aplicación se congela, mi PC se ralentiza y después de unas horas obtengo la excepción Fuera de memoria.
public List<Child> getChildren() { return em.createQuery("from Child",Child.class).getResultList(); }Miré el SQL generado y para el primer método parece desglosar lógicamente las llamadas en conjuntos individuales de objetos y durante los segundos parece construir una consulta del tamaño de un monstruo que realmente no puedo seguir y esa consulta no Parece que regresará, aunque realmente no puedo decirlo.
Lo que no puedo entender es por qué la consulta al padre funciona tan rápido y me da todos los objetos, pero la consulta del niño simplemente se rompe.
Cuando comienza con los padres, Hibernate puede leer todos los padres (simple) y unirse a la tabla secundaria (nuevamente, simple). Cada niño tiene exactamente un padre, que es con el que nos unimos, así que eso es suficiente. Si bien toda la base de datos se lee en la memoria, no hay problema ya que es pequeña.
Cuando comienza con los niños, por otro lado, Hibernate primero debe buscar el padre para cada niño. Eso significa que uno se une a la tabla principal. Sin embargo, esos padres tienen hijos, por lo que debemos unirnos nuevamente a la tabla de niños para encontrarlos.
Tus clases no están completas, falta el nombre de los padres y mencionas otras colecciones. Si las otras colecciones también están ansiosas, tendrían que buscarse con uniones para el primer nivel secundario y el segundo nivel secundario también, agregando dos uniones más por colección. ¡Eso lo convierte en una consulta muy compleja!
Podría ser una fuga de memoria causando esto. Puede aumentar su espacio de almacenamiento dinámico usando.
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
http://javarevisited.blogspot.com.ng/2011/09/javalangoutofmemoryerror-permgen-space.html
Sin embargo, es bueno saber cuál podría ser la causa de java.lang.OutOfMemoryError: espacio de almacenamiento dinámico de Java. El uso de un generador de perfiles puede ayudarlo a descubrir qué está consumiendo el tamaño del montón. Si está utilizando Netbeans, puede usar https://profiler.netbeans.org/ o encontrar un perfilador compatible con su IDE.