我正在尝试在两个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}}对象也可以。我认为所有表都设置正确。为什么我会收到此错误?
答案 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方法。