Hibernate StackOverflowError

时间:2014-09-17 13:22:56

标签: java hibernate

我正在尝试在两个Hibernate实体之间创建多对多关系。这是我的实体:

供应商:

package domain;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "supplier")
public class Supplier implements Serializable {

    private static final long serialVersionUID = -8770635537770426413L;

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

    @Column(name = "id")
    private int id;

    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(name = "supplier_project", joinColumns = { @JoinColumn(name = "supplier_name") }, inverseJoinColumns = { @JoinColumn(name = "project_name") })
    private Set<Project> projects = new HashSet<>();

    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(name = "supplier_cad_system", joinColumns = { @JoinColumn(name = "supplier_name") }, inverseJoinColumns = { @JoinColumn(name = "cad_system_name") })
    private Set<CadSystem> cadSystems = new HashSet<>();

    public Supplier() {
    }

    public Supplier(final String name, final int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(final int id) {
        this.id = id;
    }

    public Set<Project> getProjects() {
        return projects;
    }

    public void setProjects(final Set<Project> projects) {
        this.projects = projects;
    }

    public Set<CadSystem> getCadSystems() {
        return cadSystems;
    }

    public void setCadSystems(final Set<CadSystem> cadSystems) {
        this.cadSystems = cadSystems;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("Supplier[name=");
        builder.append(name);
        builder.append(", id=");
        builder.append(id);
        builder.append(", projects=");
        builder.append(projects);
        builder.append(", cadSystems=");
        builder.append(cadSystems);
        builder.append("]");

        return builder.toString();
    }

}

CadSystem:

package domain;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "cad_systems")
public class CadSystem implements Serializable {

    private static final long serialVersionUID = -777117867924204408L;

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

    @ManyToMany(mappedBy = "cadSystems")
    private Set<Supplier> suppliers = new HashSet<>();

    public CadSystem() {
    }

    public CadSystem(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public Set<Supplier> getSuppliers() {
        return suppliers;
    }

    public void setSuppliers(final Set<Supplier> suppliers) {
        this.suppliers = suppliers;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("CadSystem[name=");
        builder.append(name);
        builder.append(", suppliers=");
        builder.append(suppliers);
        builder.append("]");

        return builder.toString();
    }

}

项目:

package domain;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "project")
public class Project implements Serializable {

    private static final long serialVersionUID = 5652106258971634091L;

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

    @ManyToMany(mappedBy = "projects")
    private Set<Supplier> suppliers;

    public Project() {
    }

    public Project(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public Set<Supplier> getSuppliers() {
        return suppliers;
    }

    public void setSuppliers(final Set<Supplier> suppliers) {
        this.suppliers = suppliers;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("Project[name=");
        builder.append(name);
        builder.append("]");

        return builder.toString();
    }

}

可悲的是,我得到了StackOverflowError

Sep 17, 2014 3:10:14 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
Sep 17, 2014 3:10:14 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.6.Final}
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: /hibernate.cfg.xml
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: HHH000040: Configuration resource: /hibernate.cfg.xml
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Configuration doConfigure
INFO: HHH000041: Configured SessionFactory: null
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH000402: Using Hibernate built-in connection pool (not for production use!)
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000401: using driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] at URL [jdbc:sqlserver://****;databaseName=****]
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000046: Connection properties: {user=****, password=****}
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000006: Autocommit mode: false
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 10 (min=1)
Sep 17, 2014 3:10:37 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.SQLServer2005Dialect
Sep 17, 2014 3:10:37 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
Sep 17, 2014 3:10:37 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: 
    select
        supplier0_.name as name1_2_0_,
        supplier0_.id as id2_2_0_ 
    from
        supplier supplier0_ 
    where
        supplier0_.name=?
Hibernate: 
    select
        projects0_.supplier_name as supplier1_2_0_,
        projects0_.project_name as project_2_4_0_,
        project1_.name as name1_1_1_ 
    from
        supplier_project projects0_ 
    inner join
        project project1_ 
            on projects0_.project_name=project1_.name 
    where
        projects0_.supplier_name=?
Hibernate: 
    select
        cadsystems0_.supplier_name as supplier1_2_0_,
        cadsystems0_.cad_system_name as cad_syst2_3_0_,
        cadsystem1_.name as name1_0_1_ 
    from
        supplier_cad_system cadsystems0_ 
    inner join
        cad_systems cadsystem1_ 
            on cadsystems0_.cad_system_name=cadsystem1_.name 
    where
        cadsystems0_.supplier_name=?
Hibernate: 
    select
        suppliers0_.cad_system_name as cad_syst2_0_0_,
        suppliers0_.supplier_name as supplier1_3_0_,
        supplier1_.name as name1_2_1_,
        supplier1_.id as id2_2_1_ 
    from
        supplier_cad_system suppliers0_ 
    inner join
        supplier supplier1_ 
            on suppliers0_.supplier_name=supplier1_.name 
    where
        suppliers0_.cad_system_name=?
Exception in thread "main" java.lang.StackOverflowError
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:316)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at domain.CadSystem.toString(CadSystem.java:59)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at java.util.AbstractCollection.toString(AbstractCollection.java:450)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:317)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at domain.Supplier.toString(Supplier.java:91)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:196)
    at domain.Supplier_$$_jvste67_0.toString(Supplier_$$_jvste67_0.java)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at java.util.AbstractCollection.toString(AbstractCollection.java:450)

我尝试使用此命令获取Supplier对象:session.load(Supplier.class, "key")。如果我将所有CadSystem内容都注释掉,那就可以了。甚至存储添加了Supplier的{​​{1}}对象也可以。我认为所有表都设置正确。为什么我会收到此错误?

5 个答案:

答案 0 :(得分:2)

CadSystem#toString()Supplier#toString()之间的无限复发使StackOverflowError

为避免此错误,相关实体的toString()应仅包含id, name or/and other appropriate property info相关实体。

就像CadSystem#toString()中的这个例子一样,

for (Supplier supplier : suppliers) {
    builder.append("Supplier :[Id=" + supplier.getId() +
                              ", Name=" + supplier.getName() + "]\n");
}

答案 1 :(得分:1)

解决方案非常简单,尝试通过从所有类中删除toString()方法来运行程序。 它导致无限循环。

答案 2 :(得分:0)

附加到字符串构建器

时会出现异常

at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:316)         at java.lang.String.valueOf(String.java:2854)         在java.lang.StringBuilder.append(StringBuilder.java:128)

当线程堆栈空间不足以容纳更多变量时,就会出现堆栈溢出。 在下面的代码中,builder是一个局部变量,它存储在堆栈上,并将供应商附加到它。增加您的线程堆栈大小或检查供应商的价值,这可能很大。

builder.append(name);
        builder.append(", suppliers=");
        builder.append(suppliers);
        builder.append("]");

答案 3 :(得分:0)

我在Supplier#toString()CadSystem#toString()之间创建了无限递归。 Supplier#toString() CadSystem#toString()CadSystem#toString()再次呼叫Supplier#toString()。因此,方法永远不会终止,导致StackOverflowError

答案 4 :(得分:0)

有点题外话,但是...

如果有人遇到与lombak(Spring JPA)有关的错误,只需创建自己的toString方法。