【问题标题】:JPA with Hibernate 3 - ManyToMany-Stack overflow and Multiple bag errorsJPA with Hibernate 3 - ManyToMany-Stack 溢出和多包错误
【发布时间】:2011-04-28 14:49:43
【问题描述】:

我在为具有双向多对多关系的实体检索数据时遇到问题。如果我使用List 来存储实体,我将无法同时获取多个包错误。如果我将代码更改为使用 Set,则会出现 stackoverflow 错误。

详情:

  • 春季 3.0.3
  • 休眠核心:3.5.1-Final
  • 休眠注释:3.5.1-Final
  • hibernate-common-annotations : 3.2.0-Final
  • hibernate-entitymanager : 3.5.1-Final
  • Mysql 数据库
  • Junit 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. 当我尝试使用 JUnit 测试用例获取所有用户数据 (getAllUsers) 时,出现无法同时获取多个包的错误。
  2. 如果我分别使用 SetHashSet 而不是 List 和 ArrayList,则会出现 stackoverflow 错误。

请帮助我,让我知道代码是否错误,或者它是我正在使用的特定版本的库的已知休眠问题。

【问题讨论】:

    标签: java hibernate orm jpa-2.0


    【解决方案1】:

    我遇到了类似的问题,根本原因是上面提到的 Vjeetje 的 Lombok 生成代码。我的代码使用了注解@Data,它生成了带有交叉依赖字段的hashCode和ToString方法,这种结构导致Hibernate卡住了。所以,应该注意避免这些无限循环调用,在我的例子中,我只是添加了排除参数,比如@EqualsAndHashCode(exclude="dependent_list") 和@ToString(exclude = "dependent_list")。它解决了堆栈溢出问题。

    【讨论】:

    • 另一种方法是使用 @ToString.Exclude@EqualsAndHashCode.Exclude 注释字段
    • @arnonuem 是,但如果 Lombok 版本是 1.16.22 或更高版本
    【解决方案2】:

    您不能在两个列表上映射多对多关系,然后 hibernate 将尝试为每个嵌套元素获取一个集合,即用户列表中的每个用户都有一个银行帐户列表,其中包含一个用户列表。 ...把它想象成一个永无止境的递归。

    【讨论】:

    • 嗨,诺姆,感谢您的回复。但是我们不需要 Collection 双方,因为它是多对多的关系吗?
    • 为了让 hibernate 映射集合只需要一侧。来自休眠注释文档:“如前所述,另一方不必(不得)描述物理映射:包含所有者侧属性名称的简单 mappedBy 参数将两者绑定。”
    • 我能够通过从 toString() 方法中删除其他实体的引用来解决这个问题。即从 User 对象的 toString 方法中删除了对 BankAccount 的引用,反之亦然。我还从所有实体中删除了 fetch=fetchType.EAGER。但是,我认为 hibernate 能够检测到这种循环依赖并且不会抛出 stackoverflow 异常。
    【解决方案3】:

    (让我们暂时将fetch 属性放在一边)。您的映射是完全有效的,并且是映射双向多对多关系的正确方法。来自 JPA 2.0 规范:

    2.10.4 双向多对多关系

    ...

    示例:

    @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 能够处理 Emmanuel Bernard 的 this comment 中提到的循环:

    LAZY 或 EAGER 应该与代码库中的无限循环问题正交。 Hibernate 知道如何处理循环图

    有趣的是,我最近回答了a very similar question(非常接近的问题)。 也许暗示 Hibernate 出了点问题(我对上述评论的理解是在双方都使用 EAGER fetching 应该可以工作)。

    因此,我将以同样的方式结束我的回答:如果您可以提供允许重现问题的测试用例,请打开 Jira 问题。

    【讨论】:

    • 我已经为这个问题添加了 JIRA 以及完整的源代码 opensource.atlassian.com/projects/hibernate/browse/HHH-5691
    • 我在两个实体之间的多对多关系上使用 Lombok 的 ToSring 注释时遇到了一个非常相似的问题。解决方法:使用 ToString 注解的 exclude 属性。无论如何,Hibernate 可以很好地处理双方都急切获取的多对多关系。
    【解决方案4】:

    我也遇到了同样的问题。

    问题在于我来自 lombok 库的 @Data 注释。

    为了解决这个问题,我将@Data 替换为@Getter、@Setter。并在该类上定义了一个自定义的 toString() 方法。

    【讨论】:

      猜你喜欢
      • 2023-03-15
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 2020-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多