带有额外列的连接表的Hibernate @ManyToOne似乎会生成无限循环

时间:2014-12-29 17:33:10

标签: spring hibernate jpa

我有3个实体:Contract,Person和ContractPerson。 ContractPerson是Contract和Person之间的连接表,带有额外的字段,因此我创建了一个单独的实体。

Contract.java:

   import lombok.Data;
   import javax.persistence.*;
   import java.util.HashSet;
   import java.util.Set;

   @Data
   @Entity
   @Table (name = "contract")
   public class Contract {

       @Id
       @GeneratedValue
       @Column (name = "contract_id")
       private Long id;

       @Column (name = "contract_ref")
       private String ref;

       @OneToMany (mappedBy = "contract", fetch = FetchType.LAZY)
       private Set<ContractPerson> contractPersons = new HashSet<>();
    }

Person.java:

   import lombok.Data;
   import javax.persistence.*;

   @Data
   @Entity
   @Table (name = "person")
   public class Person {

       @Id
       @GeneratedValue
       @Column (name = "person_id")
       private Long id;

       @Column (name = "formality")
       private String formality;

       @Column (name = "first_name")
       private String firstName;

       @Column (name = "last_name")
       private String lastName;

       @OneToMany (mappedBy = "person", fetch = FetchType.LAZY)
       private Set<ContractPerson> contractPersons = new HashSet<>();
    }

ContractPerson.java:

import lombok.Data;

import javax.persistence.*;

@Data
@Entity
@Table (name = "contract_person")
public class ContractPerson {

    @Id
    @GeneratedValue
    @Column (name = "contract_person_id")
    private Long id;

    @Column (name = "description")
    private String description;

    @ManyToOne
    @JoinColumn (name = "id_of_person")
    private Person person;

    @ManyToOne
    @JoinColumn (name = "id_of_contract")
    private Contract contract;
}

当我尝试使用Spring Data JPA获得具有特定id的合同时,它会生成这种输入:

2014-12-29 18:02:10.843 DEBUG 1932 --- [qtp745716999-20] e.p.i.CollectionReferenceInitializerImpl : Found row of collection: [xxx.Contract.contractPersons#199]
2014-12-29 18:02:10.843 DEBUG 1932 --- [qtp745716999-20] o.h.e.l.internal.CollectionLoadContext   : 1 collections were found in result set for role: xxx.Contract.contractPersons
2014-12-29 18:02:10.843 DEBUG 1932 --- [qtp745716999-20] stractLoadPlanBasedCollectionInitializer : Loading collection: [xxx.Contract.contractPersons#199]
2014-12-29 18:02:10.879 DEBUG 1932 --- [qtp745716999-20] o.h.l.p.e.p.i.ResultSetProcessorImpl     : Preparing collection intializer : [xxx.Contract.contractPersons#199]
2014-12-29 18:02:10.879 DEBUG 1932 --- [qtp745716999-20] o.h.l.p.e.p.i.ResultSetProcessorImpl     : Starting ResultSet row #0
2014-12-29 18:02:10.879 DEBUG 1932 --- [qtp745716999-20] e.p.i.CollectionReferenceInitializerImpl : Found row of collection: [xxx.Contract.contractPersons#199]
2014-12-29 18:02:10.880 DEBUG 1932 --- [qtp745716999-20] o.h.l.p.e.p.i.ResultSetProcessorImpl     : Starting ResultSet row #1
2014-12-29 18:02:10.880 DEBUG 1932 --- [qtp745716999-20] e.p.i.CollectionReferenceInitializerImpl : Found row of collection: [xxx.Contract.contractPersons#199]
2014-12-29 18:02:10.880 DEBUG 1932 --- [qtp745716999-20] o.h.e.l.internal.CollectionLoadContext   : 1 collections were found in result set for role: xxx.Contract.contractPersons
etc...

在重复这个日志之后,我有了这个:

2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@53504a5c<rs=com.mysql.jdbc.JDBC4ResultSet@448cef4b>
2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@3c4208bf<rs=com.mysql.jdbc.JDBC4ResultSet@55932a51>
2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@134c5281<rs=com.mysql.jdbc.JDBC4ResultSet@44927753>
2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@77bc9d0c<rs=com.mysql.jdbc.JDBC4ResultSet@6520ed53>
2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@7feabc3d<rs=com.mysql.jdbc.JDBC4ResultSet@6a97c953>
2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@bec8a67<rs=com.mysql.jdbc.JDBC4ResultSet@4e0d0b57>
2014-12-29 18:25:41.805  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@5672764e<rs=com.mysql.jdbc.JDBC4ResultSet@1d0c0d57>
2014-12-29 18:25:41.806  WARN 1992 --- [tp2080715589-19] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@74b52738<rs=com.mysql.jdbc.JDBC4ResultSet@5ee5b357>

如果我删除合同中的链接,则没有错误。

你知道吗?无限循环 ?其他?

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

@ToString中的主要问题是,由于@OneToManyPerson之间具有Contract关系,因此它会经历无限循环,如果您对其进行调试,则将可能看到StackOverflowException被抛在了后面。由于@Data是方便的快捷方式注释,将@ToString@EqualsAndHashCode@Getter / @Setter@RequiredArgsConstructor的功能捆绑在一起。因此,最好的方法是分别使用这些批注并忽略@ToString而不是如下使用@Data

Contract.java:

import lombok.Data;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@RequiredArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
@Entity
@Table (name = "contract")
public class Contract {

    @Id
    @GeneratedValue
    @Column (name = "contract_id")
    private Long id;

    @Column (name = "contract_ref")
    private String ref;

    @OneToMany (mappedBy = "contract", fetch = FetchType.LAZY)
    private Set<ContractPerson> contractPersons = new HashSet<>();
}

Person.java:

import lombok.Data;
import javax.persistence.*;

@RequiredArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
@Entity
@Table (name = "person")
public class Person {

    @Id
    @GeneratedValue
    @Column (name = "person_id")
    private Long id;

    @Column (name = "formality")
    private String formality;

    @Column (name = "first_name")
    private String firstName;

    @Column (name = "last_name")
    private String lastName;

    @OneToMany (mappedBy = "person", fetch = FetchType.LAZY)
    private Set<ContractPerson> contractPersons = new HashSet<>();
}

ContractPerson.java:

import lombok.Data;
import javax.persistence.*;

@RequiredArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
@Entity
@Table (name = "contract_person")
public class ContractPerson {

    @Id
    @GeneratedValue
    @Column (name = "contract_person_id")
    private Long id;

    @Column (name = "description")
    private String description;

    @ManyToOne
    @JoinColumn (name = "id_of_person")
    private Person person;

    @ManyToOne
    @JoinColumn (name = "id_of_contract")
    private Contract contract;
}