JPA с Hibernate 3 — переполнение ManyToMany-Stack и множественные ошибки пакетов

Я сталкиваюсь с проблемами при извлечении данных для сущностей, имеющих двунаправленные отношения «многие ко многим». Если я использую List для хранения сущностей, я не могу получить несколько пакетов одновременно. Если я изменю свой код, чтобы использовать Set, я получу ошибку stackoverflow.

Подробности :

  • Весна 3.0.3
  • Hibernate-core: 3.5.1-Final
  • Hibernate-аннотации: 3.5.1-Final
  • hibernate-common-аннотации: 3.2.0-Final
  • hibernate-entitymanager: 3.5.1-Final
  • База данных MySQL
  • 4 июня

У пользователя много банковских счетов; Банковский счет может иметь много пользователей

Пользователь.java

@ManyToMany(fetch = FetchType.EAGER, mappedBy="user") 
private List<BankAccount> bankAccounts = new ArrayList<BankAccount>();

BankAccount.java

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_bankaccount", 
           joinColumns = @JoinColumn(name="bank_account_id"), 
           inverseJoinColumns = @JoinColumn(name = "user_id")
)
private List<User> user = new ArrayList<User>();

Таблицы БД

Users
user_id PK

Bankaccount
bank_account_id PK

user_bankaccount
bank_account_id PK ( references bankaccount.bank_account_id )
user_id PK ( references user.user_id )

вопросы

  1. когда я пытаюсь получить все данные пользователей (getAllUsers) с помощью тестового примера JUnit, я не могу получить несколько пакетов одновременно.
  2. Если я использую Set и HashSet вместо списка и ArrayList соответственно, я получаю ошибку переполнения стека.

Пожалуйста, помогите мне и дайте мне знать, если код неверен или это известная проблема со спящим режимом с определенной версией библиотек, которые я использую.


person Suyash    schedule 21.10.2010    source источник


Ответы (4)


Я столкнулся с аналогичной проблемой, и основной причиной является код генерации Lombok, как упоминалось выше Vjeetje. В моем коде используется аннотация @Data, которая генерирует методы hashCode и ToString с перекрестно-зависимыми полями, и эта структура приводит к зависанию Hibernate. Таким образом, следует избегать этих вызовов бесконечного цикла, в моем случае я просто добавил параметры исключения, такие как @EqualsAndHashCode(exclude="depended_list") и @ToString(exclude = "dependent_list"). Это решает проблему переполнения стека.

person kolya_metallist    schedule 08.07.2019
comment
Альтернативой является аннотирование полей с помощью @ToString.Exclude и @EqualsAndHashCode.Exclude. - person arnonuem; 17.03.2020
comment
@arnonuem Да, но если версия Lombok 1.16.22 или выше - person kolya_metallist; 19.03.2020

Вы не можете сопоставить отношения «многие ко многим» в обоих списках, затем hibernate попытается получить коллекцию для каждого вложенного элемента, т.е. у каждого пользователя в списке пользователей есть список банковских счетов, у которых есть список пользователей.... подумайте об этом как о бесконечной рекурсии.

person Noam Nevo    schedule 21.10.2010
comment
Привет, Ноам, спасибо за ваш ответ. Но разве нам не нужна коллекция с обеих сторон, поскольку это отношения «многие ко многим»? - person Suyash; 21.10.2010
comment
для того, чтобы hibernate отображал коллекции, требуется только одна сторона. из документации по аннотации гибернации: как было показано ранее, другая сторона не должна (не должна) описывать физическое сопоставление: простой аргумент mappedBy, содержащий имя свойства на стороне владельца, связывает их. - person Noam Nevo; 21.10.2010
comment
Мне удалось решить проблему, удалив ссылки на другой объект из метода toString(). то есть удалены ссылки на BankAccount из метода toString объекта User и наоборот. Я также удалил fetch=fetchType.EAGER из всех сущностей. Однако я думал, что hibernate может обнаруживать такую ​​циклическую зависимость и не вызывать исключение stackoverflow. - person Suyash; 27.10.2010

(Давайте пока оставим атрибут fetch в стороне). Ваше сопоставление совершенно верно и является правильным способом сопоставления двунаправленных отношений «многие ко многим». Из спецификации JPA 2.0:

2.10.4 Двунаправленные отношения ManyToMany

...

Пример:

@Entity
public class Project {
    private Collection<Employee> employees;

    @ManyToMany
    public Collection<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(Collection<Employee> employees) {
        this.employees = employees;
    }
    ...
}

@Entity
public class Employee {
    private Collection<Project> projects;

    @ManyToMany(mappedBy="employees")
    public Collection<Project> getProjects() {
        return projects;
    }
    public void setProjects(Collection<Project> projects) {
        this.projects = projects;
    }
    ...
}

В этом примере:

  • Объект Project ссылается на набор объектов Employee.
  • Объект Employee ссылается на набор объектов Project.
  • Объект Project является владельцем отношения.

...

При этом я не уверен в поведении при использовании EAGER выборки с обеих сторон (приведет ли это к бесконечному циклу?), спецификация JPA довольно размыта по этому поводу, и я не могу найти любое четкое упоминание о том, что это запрещено. Но держу пари, что это часть проблемы.

Но в конкретном случае Hibernate я ожидаю, что Hibernate сможет обрабатывать циклы, как указано в этот комментарий от Эммануэля Бернара:

LAZY или EAGER должны быть ортогональны проблеме с бесконечным циклом в кодовой базе. Hibernate умеет обрабатывать циклические графы

Как ни странно, недавно я ответил на очень похожий вопрос (очень закрыть проблему). Возможно, намек на то, что в Hibernate что-то не так (насколько я понимаю приведенный выше комментарий, использование выборки EAGER с обеих сторон должно работать).

Таким образом, я завершу свой ответ таким же образом: если вы можете предоставить тестовый пример, позволяющий воспроизвести проблему, откройте задачу Jira.

person Pascal Thivent    schedule 21.10.2010
comment
Я добавил JIRA для этой проблемы вместе с полным исходным кодом opensource.atlassian.com/projects /hibernate/browse/HHH-5691 - person Suyash; 26.10.2010
comment
У меня была очень похожая проблема с использованием аннотации Lombok ToSring для отношения «многие ко многим» между двумя объектами. Решение: используйте атрибут exclude аннотации ToString. В любом случае, Hibernate может отлично работать с отношениями «многие ко многим», когда обе стороны активно извлекаются. - person Vjeetje; 28.01.2016

Я также столкнулся с той же проблемой.

Проблема была с моей аннотацией @Data из библиотеки lombok.

Чтобы это исправить, я заменил @Data на @Getter, @Setter. И определил собственный метод toString() в классе.

person P. Beri    schedule 08.09.2020