Hibernate lanza esta excepción durante la creación de SessionFactory:
org.hibernate.loader.MultipleBagFetchException: no puede recuperar simultáneamente varias bolsas
Este es mi caso de prueba:
Parent.java
@Entity
public Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
// @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null.
private List<Child> children;
}
Child.java
@Entity
public Child {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
¿Qué tal este problema? ¿Que puedo hacer?
EDITAR
OK, el problema que tengo es que hay otra entidad "padre" dentro de mi padre, mi comportamiento real es este:
Parent.java
@Entity
public Parent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@ManyToOne
private AnotherParent anotherParent;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<Child> children;
}
AnotherParent.java
@Entity
public AnotherParent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
private List<AnotherChild> anotherChildren;
}
A Hibernate no le gustan dos colecciones FetchType.EAGER, pero esto parece ser un error, no estoy haciendo cosas inusuales ...
La eliminación FetchType.EAGERdel Parento AnotherParentresuelve el problema, sino que lo necesita, por lo que verdadera solución es utilizar @LazyCollection(LazyCollectionOption.FALSE)en lugar de FetchType(gracias a Bozho para la solución).

select * from master; select * from child1 where master_id = :master_id; select * from child2 where master_id = :master_idList<child>con lafetchTypedefinida por más de unaList<clield>Respuestas:
Creo que una versión más nueva de hibernate (compatible con JPA 2.0) debería manejar esto. Pero de lo contrario, puede solucionarlo anotando los campos de recopilación con:
Recuerde eliminar el
fetchTypeatributo de la@*ToManyanotación.Pero tenga en cuenta que en la mayoría de los casos a
Set<Child>es más apropiado queList<Child>, por lo tanto, a menos que realmente necesite unList- vaya aSetPero recuerde que con el uso de conjuntos no eliminará la capa subyacente Producto cartesiano como lo describe Vlad Mihalcea en su respuesta !
fuente
fetchTypede la@*ToMany?Simplemente cambie de
Listtipo aSettipo.¡Pero recuerde que no eliminará el Producto cartesiano subyacente como lo describe Vlad Mihalcea en su respuesta !
fuente
*ToMany. Cambiar el tipo paraSetresolver mi problema también. Excelente y ordenada solución. Esta debería ser la respuesta oficial.Agregue una anotación @Fetch específica de Hibernate a su código:
Esto debería solucionar el problema relacionado con el error de Hibernate HHH-1718
fuente
Setrealmente tenga sentido. Tener una solaOneToManyrelación utilizandoSetresultados en1+<# relationships>consultas, mientras que utilizandoFetchMode.SUBSELECTresultados en1+1consultas. Además, el uso de la anotación en la respuesta aceptada (LazyCollectionOption.FALSE) hace que se ejecuten incluso más consultas.Teniendo en cuenta que tenemos las siguientes entidades:
Y quieres traer a algún padre
Postentidades junto con todos loscommentsytagscolecciones .Si está usando más de uno
JOIN FETCHdirectiva:Hibernate arrojará a los infames:
Hibernate no permite buscar más de una bolsa porque eso generaría un producto cartesiano .
La peor "solución"
Ahora, encontrará muchas respuestas, publicaciones de blog, videos u otros recursos que le indican que use un en
Setlugar de unListpara sus colecciones.Ese es un consejo terrible. ¡No hagas eso!
Usar en
Setslugar deListshará que elMultipleBagFetchExceptiondesaparezca, pero el Producto cartesiano seguirá estando allí, lo que en realidad es aún peor, ya que descubrirá el problema de rendimiento mucho después de aplicar esta "solución".La solución adecuada
Puedes hacer el siguiente truco:
Siempre que obtenga como máximo una colección usando
JOIN FETCH, estará bien.Al utilizar múltiples consultas, evitará el Producto cartesiano ya que cualquier otra colección, pero la primera se obtiene mediante una consulta secundaria.
Hay más que puedes hacer
Si está utilizando la
FetchType.EAGERestrategia en el momento del mapeo@OneToManyo las@ManyToManyasociaciones, podría terminar fácilmente con unMultipleBagFetchException.Es mejor cambiar de
FetchType.EAGERa,Fetchype.LAZYya que la búsqueda ansiosa es una idea terrible que puede conducir a problemas críticos de rendimiento de la aplicación .Conclusión
Evita
FetchType.EAGERy no cambiesListaSetsolo porque hacerlo hará que Hibernate escondaMultipleBagFetchExceptiondebajo de la alfombra. Obtenga solo una colección a la vez y estará bien.Siempre que lo haga con la misma cantidad de consultas que las colecciones para inicializar, está bien. Simplemente no inicialice las colecciones en un bucle, ya que eso provocará problemas de consulta N + 1 , que también son malos para el rendimiento.
fuente
DISTINCTes asesino de rendimiento en esta solución. ¿Hay alguna forma de deshacerse de éldistinct? (Intenté regresarSet<...>, no ayudó mucho)PASS_DISTINCT_THROUGHestá configurado comofalse. DISTINCT tiene 2 significados en JPQL, y aquí, lo necesitamos para deduplicar en el lado de Java, no en el lado de SQL. Mira este artículo para más detalles.hibernate.jdbc.fetch_size(eventualmente lo configuré en 350). Por casualidad, ¿sabes cómo optimizar las relaciones anidadas? Por ejemplo, entidad1 -> entidad2 -> entidad3.1, entidad 3.2 (donde entidad3.1 / 3.2 son relaciones @OneToMany)Después de probar con todas las opciones descritas en estas publicaciones y en otras, llegué a la conclusión de que la solución es la siguiente.
En cada lugar de XToMany @
XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)e intermediamente despuésEsto funciono para mi
fuente
@Fetch(value = FetchMode.SUBSELECT)fue suficientePara solucionarlo, simplemente tome el
Setlugar deListsu objeto anidado.y no olvides usar
fetch=FetchType.EAGERfuncionará.
Hay un concepto mas
CollectionIden Hibernate si desea seguir solo con la lista.¡Pero recuerde que no eliminará el Producto cartesiano subyacente como lo describe Vlad Mihalcea en su respuesta !
fuente
Encontré una buena publicación de blog sobre el comportamiento de Hibernate en este tipo de asignaciones de objetos: http://blog.eyallupu.com/2010/06/hibernate-exception-sim simultáneamente.html
fuente
puede mantener listas EAGER de stand en JPA y agregar al menos a una de ellas la anotación JPA @OrderColumn (obviamente con el nombre de un campo que se debe ordenar). No necesita anotaciones específicas de hibernación. Pero tenga en cuenta que podría crear elementos vacíos en la lista si el campo elegido no tiene valores que comiencen desde 0
en Niños, entonces debe agregar el campo orderIndex
fuente
Intentamos Set en lugar de List y es una pesadilla: cuando agrega dos objetos nuevos, equals () y hashCode () no logran distinguirlos a ambos. Porque no tienen ninguna identificación.
Las herramientas típicas como Eclipse generan ese tipo de código de las tablas de la base de datos:
También puede leer este artículo que explica correctamente qué tan desordenado es JPA / Hibernate. Después de leer esto, creo que es la última vez que uso un ORM en mi vida.
También me he encontrado con tipos de diseño impulsado por dominio que básicamente dicen que ORM es algo terrible.
fuente
Cuando tenga objetos demasiado complejos con una colección saveral, no podría ser una buena idea tenerlos todos con EAGER fetchType, mejor use LAZY y cuando realmente necesite cargar las colecciones, use:
Hibernate.initialize(parent.child)para buscar los datos.fuente
Para mí, el problema era haber anidado las recuperaciones de EAGER .
Una solución es establecer los campos anidados en LAZY y usar Hibernate.initialize () para cargar los campos anidados:
fuente
Al final, esto sucedió cuando tuve varias colecciones con FetchType.EAGER, así:
Además, las colecciones se unieron en la misma columna.
Para resolver este problema, cambié una de las colecciones a FetchType.LAZY ya que estaba bien para mi caso de uso.
¡Buena suerte! ~ J
fuente
Comentando ambos
Fetchy aLazyCollectionveces ayuda a ejecutar el proyecto.fuente
Una cosa buena
@LazyCollection(LazyCollectionOption.FALSE)es que varios campos con esta anotación pueden coexistir mientrasFetchType.EAGERque no pueden, incluso en las situaciones en que dicha coexistencia es legítima.Por ejemplo, un
Orderpuede tener una lista deOrderGroup(una corta) así como una lista dePromotions(también corta).@LazyCollection(LazyCollectionOption.FALSE)se puede usar en ambos sin causarLazyInitializationExceptionningunoMultipleBagFetchException.En mi caso
@Fetchresolvió mi problemaMultipleBacFetchExceptionpero luego causaLazyInitializationExceptionel infameno Sessionerror.fuente
Podría usar una nueva anotación para resolver esto:
De hecho, el valor predeterminado de fetch también es FetchType.LAZY.
fuente