Hibernate выдает это исключение при создании SessionFactory:
org.hibernate.loader.MultipleBagFetchException: невозможно одновременно получить несколько пакетов
Это мой тестовый пример:
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;
}
Как насчет этой проблемы? Что я могу сделать?
РЕДАКТИРОВАТЬ
ОК, у меня проблема в том, что другая «родительская» сущность находится внутри моего родителя, мое реальное поведение таково:
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;
}
Hibernate не любит две коллекции с FetchType.EAGER
, но это, кажется, ошибка, я не делаю необычных вещей ...
Удаление FetchType.EAGER
из Parent
или AnotherParent
решает проблемы, но мне это нужно, поэтому реальное решение заключается в использовании @LazyCollection(LazyCollectionOption.FALSE)
вместо FetchType
(спасибо Bozho для решения).
select * from master; select * from child1 where master_id = :master_id; select * from child2 where master_id = :master_id
List<child>
сfetchType
определенным для более чем одногоList<clield>
Ответы:
Я думаю, что более новая версия hibernate (поддерживающая JPA 2.0) должна справиться с этим. Но в противном случае вы можете обойти это, пометив поля коллекции с помощью:
Не забудьте удалить
fetchType
атрибут из@*ToMany
аннотации.Но обратите внимание , что в большинстве случаев
Set<Child>
является более подходящим , чемList<Child>
, так что если вы действительно не нуженList
- дерзайтеSet
Но напомните, что при использовании наборов вы не будете устранять нижележащий декартов продукт, как описано Владом Михалчей в его ответе !
источник
fetchType
из@*ToMany
?Просто измените от
List
типа кSet
типу.Но напомните, что вы не будете устранять нижележащее декартово произведение, описанное Владом Михалчей в его ответе !
источник
*ToMany
. Изменение типа, чтобыSet
решить мою проблему тоже. Отличное и аккуратное решение. Это должен быть официальный ответ.Добавьте специфичную для Hibernate аннотацию @Fetch в свой код:
Это должно исправить проблему, связанную с ошибкой Hibernate HHH-1718
источник
Set
не имеет смысла. Наличие единственнойOneToMany
связи с использованиемSet
результатов в1+<# relationships>
запросах, где использованиеFetchMode.SUBSELECT
результатов в1+1
запросах. Кроме того, использование аннотации в принятом ответе (LazyCollectionOption.FALSE
) приводит к выполнению еще большего количества запросов.Учитывая, что у нас есть следующие объекты:
И, вы хотите загрузить некоторые родительские
Post
объекты вместе со всемиcomments
иtags
коллекциями.Если вы используете более одной
JOIN FETCH
директивы:Hibernate бросит печально известную
Hibernate не позволяет получить более одной сумки, потому что это может привести к декартовому продукту .
Худшее «решение»
Теперь вы найдете множество ответов, сообщений в блогах, видео или других ресурсов, в которых вам предлагается использовать
Set
вместоList
своих коллекций.Это ужасный совет. Не делай этого!
Использование
Sets
вместо тогоLists
, чтобыMultipleBagFetchException
уйти, но декартово произведение будет все еще там, что на самом деле еще хуже, так как вы обнаружите проблему производительности еще долго после того, как вы применили это «исправление».Правильное решение
Вы можете сделать следующий трюк:
Пока вы выбираете не более одной коллекции
JOIN FETCH
, все будет в порядке.Используя несколько запросов, вы избежите декартово произведение, поскольку любая другая коллекция, кроме первой, извлекается с использованием вторичного запроса.
Ты можешь сделать больше
Если вы используете
FetchType.EAGER
стратегию на отображение времени@OneToMany
или@ManyToMany
ассоциаций, то вы могли бы легко закончить сMultipleBagFetchException
.Вам лучше перейти с
FetchType.EAGER
на,Fetchype.LAZY
так как активная выборка - ужасная идея, которая может привести к критическим проблемам производительности приложений .Вывод
Избегайте
FetchType.EAGER
и не переходить отList
кSet
только потому , что делать это будет сделать Hibernate скрытьMultipleBagFetchException
под ковром. Принеси только одну коллекцию за раз, и все будет хорошо.Пока вы делаете это с тем же количеством запросов, что и у вас для инициализации коллекций, у вас все в порядке. Только не инициализируйте коллекции в цикле, поскольку это вызовет проблемы с N + 1 запросами , которые также ухудшают производительность.
источник
DISTINCT
это снижение производительности в этом решении. Есть ли способ избавиться отdistinct
? (пытался вернутьсяSet<...>
вместо этого, не помогло)PASS_DISTINCT_THROUGH
установленоfalse
. DISTINCT имеет два значения в JPQL, и здесь нам нужно его дедуплицировать на стороне Java, а не на стороне SQL. Проверьте эту статью для более подробной информации.hibernate.jdbc.fetch_size
(в конце концов я установил его на 350). Вы случайно не знаете, как оптимизировать вложенные отношения? Например, entity1 -> entity2 -> entity3.1, entity 3.2 (где entity3.1 / 3.2 - отношения @OneToMany)После попыток описать каждую опцию в этом и других постах, я пришел к выводу, что исправление заключается в следующем.
В каждом месте XToMany @
XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)
и послеЭто сработало для меня
источник
@Fetch(value = FetchMode.SUBSELECT)
было достаточноЧтобы исправить это просто взять
Set
вместоList
для вложенного объекта.и не забудьте использовать
fetch=FetchType.EAGER
это будет работать.
В
CollectionId
Hibernate есть еще одна концепция, если вы хотите придерживаться только списка.Но напомните, что вы не будете устранять нижележащее декартово произведение, описанное Владом Михалчей в его ответе !
источник
Я нашел хороший пост в блоге о поведении Hibernate в такого рода сопоставлениях объектов: http://blog.eyallupu.com/2010/06/hibernate-exception-simchronously.html
источник
Вы можете сохранить списки EAGER в JPA и добавить по крайней мере к одному из них аннотацию JPA @OrderColumn (очевидно, с именем поля, которое нужно упорядочить). Нет необходимости в специальных спящих аннотациях. Но имейте в виду, что это может создать пустые элементы в списке, если выбранное поле не имеет значений, начинающихся с 0
в Children, тогда вы должны добавить поле orderIndex
источник
Мы попробовали Set вместо List, и это кошмар: когда вы добавляете два новых объекта, equals () и hashCode () не могут различить их оба! Потому что у них нет идентификатора.
Типичные инструменты, такие как Eclipse, генерируют такой код из таблиц базы данных:
Вы также можете прочитать эту статью, которая правильно объясняет, как испортился JPA / Hibernate. Прочитав это, я думаю, что это последний раз, когда я использую ORM в своей жизни.
Я также встречал ребят из Domain Driven Design, которые в основном говорят, что ORM - ужасная вещь.
источник
Когда у вас есть слишком сложные объекты с коллекцией saveral, не может быть хорошей идеей иметь все их с EAGER fetchType, лучше использовать LAZY, а когда вам действительно нужно загрузить коллекции, используйте:
Hibernate.initialize(parent.child)
для получения данных.источник
Для меня проблема заключалась в том, что у меня были вложенные EAGER .
Одно из решений - установить для вложенных полей значение LAZY и использовать Hibernate.initialize () для загрузки вложенных полей:
источник
В конце концов, это случилось, когда у меня было несколько коллекций с FetchType.EAGER, например:
Кроме того, коллекции объединялись в одном столбце.
Чтобы решить эту проблему, я изменил одну из коллекций на FetchType.LAZY, так как она подходила для моего варианта использования.
Удачи! ~ J
источник
Комментирование
Fetch
иLazyCollection
иногда помогает запустить проект.источник
Одна хорошая вещь о
@LazyCollection(LazyCollectionOption.FALSE)
том, что несколько полей с этой аннотацией могут сосуществовать, ноFetchType.EAGER
не могут, даже в ситуациях, когда такое сосуществование является законным.Например,
Order
может иметь списокOrderGroup
(короткий), а также списокPromotions
(также короткий).@LazyCollection(LazyCollectionOption.FALSE)
может использоваться на обоих, не вызываяLazyInitializationException
ни того, ни другогоMultipleBagFetchException
.В моем случае
@Fetch
действительно решить мою проблему,MultipleBacFetchException
но затем причиныLazyInitializationException
, печально известнуюno Session
ошибку.источник
Вы можете использовать новую аннотацию, чтобы решить это:
Фактически, значением по умолчанию для fetch также является FetchType.LAZY.
источник