我有两个实体,让我们命名为University
和Student
,Student
是单向ManyToOne
与University
他们都扩展基类BasicUUIDEntity
:
@MappedSuperclass
public class BasicUUIDEntity implements Serializable {
protected UUID id;
@Id
@Column(name = "id", columnDefinition = "binary(16)")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BasicUUIDEntity that = (BasicUUIDEntity) o;
return id == null || id.equals(that.id);
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
Student
和University
的结构并不重要,重要的是:Student.class:
@Entity
@Table(name = "students")
public static class Student extends BasicUUIDEntity {
private University univ;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "univ_id", referencedColumnName = "id")
public University getUniversity() {
return univ;
}
public void setUniversity(University univ) {
this.univ = univ;
}
}
University.class:
@Entity
@Table(name = "universities")
public static class University extends BasicUUIDEntity {
//of course it does contain some fields, but they are strings, etc.
}
表格创建如下:
CREATE TABLE students
(
id BINARY(16) NOT NULL,
univ_id BINARY(16),
PRIMARY KEY (id),
CONSTRAINT FK_STUDENT_UNIV
FOREIGN KEY (univ_id) REFERENCES memory_type (id)
ON DELETE SET NULL
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
CREATE TABLE universities
(
id BINARY(16) NOT NULL,
PRIMARY KEY (id)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8;
问题有时,在极少数情况下,Hibernate不提取University
实体和Student
,这意味着当我做student.getUniversity()
它返回null
,而在调试器中它也是null
。但是students
表包含与univ_id
预期的University
完全相同的student
,大学也包含id
。我完全相信hibernate会话没有关闭,我试图执行与hibernate完全相同的查询,它确实返回了大学的预期id
,加入它们等等。事情就是大多数时候它确实运行良好,并且由于未知原因很少发生此类问题,更奇怪的是该表确实包含该id,因此看起来它不是MySQL问题。另外值得一提的是,我使用的是Spring Data JPA。有没有人遇到过这种行为?可能是由于继承/数据JPA / Java 9 /其他什么?
PS。请忽略代码中的任何拼写错误,这只是一个例子
版本:
Hibernate: 5.2.12.Final,
Spring Data JPA: 2.0.5.RELEASE,
HikariCP: 2.7.8,
MySQL connector: 6.0.6,
Java: 9
MySQL: Ver 14.14 Distrib 5.7.21
终于解决了
tl;博士
把fetch = FetchType.LAZY
放到ManyToOne
关系中,所以在我的例子中它变成:
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "univ_id", referencedColumnName = "id")
public University getUniversity() {
return univ;
}
描述
我不确定为什么它会像这样,但似乎Hibernate根本没有提取many-to-one
关系,如果他们渴望的话。它有一定的意义,因为这样会有循环依赖,但我认为PersistenceSet
将处理这些问题。更奇怪的是 - 如果我使用Long而不是UUID,那么相同的结构实际上可以在没有急切提取的情况下工作。