【发布时间】:2020-07-01 19:33:07
【问题描述】:
我遇到了一个非常有趣的场景。我知道 n+1 问题以及 FetchType.EAGER 和 FetchMode.JOIN。 我有一个父实体学校,它有 2 个@OneToMany 子实体,即学生和教师。我需要全部 3 个,所以使用 FetchType.EAGER 和 FetchMode.JOIN。
学校实体
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import javax.persistence.*;
import java.util.Set;
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class School {
@Id
@GeneratedValue(generator = "sequence", strategy = GenerationType.IDENTITY)
@SequenceGenerator(name = "sequence", allocationSize = 10)
int schoolId;
String schoolName;
float schoolRating;
@OneToMany(mappedBy = "school", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<Teacher> teachers;
@OneToMany(mappedBy = "school", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<Student> students;
}
学生实体
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Student {
@Id
@GeneratedValue(generator = "sequence", strategy = GenerationType.IDENTITY)
@SequenceGenerator(name = "sequence", allocationSize = 10)
public int studentId;
public byte studentByte;
public Date date;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "schoolId", referencedColumnName = "schoolId")
private School school;
}
教师实体
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Teacher {
@Id
@GeneratedValue(generator = "sequence", strategy = GenerationType.IDENTITY)
@SequenceGenerator(name = "sequence", allocationSize = 10)
public int teacherId;
public byte teacherByte;
public Date date;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "schoolId", referencedColumnName = "schoolId")
private School school;
}
学校回购
@Repository
public interface SchoolRepository extends JpaRepository<School, Integer> {
List<School>findBySchoolName(String schoolName);
}
如果我通过findById方法得到School对象,即表的主键。
Optional<School> schoolById = schoolRepository.findById(1);
生成的 SQL 是学校、学生和教师实体的连接。
select school0_.schoolId as schoolid1_0_0_, school0_.schoolName as schoolna2_0_0_, school0_.schoolRating as schoolra3_0_0_, students1_.schoolId as schoolid4_1_1_, students1_.studentId as studenti1_1_1_, students1_.studentId as studenti1_1_2_, students1_.date as date2_1_2_, students1_.schoolId as schoolid4_1_2_, students1_.studentByte as studentb3_1_2_, teachers2_.schoolId as schoolid4_2_3_, teachers2_.teacherId as teacheri1_2_3_, teachers2_.teacherId as teacheri1_2_4_, teachers2_.date as date2_2_4_, teachers2_.schoolId as schoolid4_2_4_, teachers2_.teacherByte as teacherb3_2_4_ from School school0_ left outer join Student students1_ on school0_.schoolId=students1_.schoolId left outer join Teacher teachers2_ on school0_.schoolId=teachers2_.schoolId where school0_.schoolId=?
但是如果我找到一所学校有其他一些不是主键的变量。
List<School> schoolByName = schoolRepository.findBySchoolName("school1");
生成的 SQL 是对 DB 的 3 个不同的命中。
Hibernate: select school0_.schoolId as schoolid1_0_, school0_.schoolName as schoolna2_0_, school0_.schoolRating as schoolra3_0_ from School school0_ where school0_.schoolName=?
Hibernate: select teachers0_.schoolId as schoolid4_2_0_, teachers0_.teacherId as teacheri1_2_0_, teachers0_.teacherId as teacheri1_2_1_, teachers0_.date as date2_2_1_, teachers0_.schoolId as schoolid4_2_1_, teachers0_.teacherByte as teacherb3_2_1_ from Teacher teachers0_ where teachers0_.schoolId=?
Hibernate: select students0_.schoolId as schoolid4_1_0_, students0_.studentId as studenti1_1_0_, students0_.studentId as studenti1_1_1_, students0_.date as date2_1_1_, students0_.schoolId as schoolid4_1_1_, students0_.studentByte as studentb3_1_1_ from Student students0_ where students0_.schoolId=?
我意识到只有在我们通过 id 即主键获取时加入才有效,但我没有 School 的主键。我有学校的名称,它是唯一的和索引的,也需要学生实体和教师实体。有没有办法让他们都在休眠中使用加入。我知道如果学生和老师的记录更多,那将是性能下降,但就我而言,最多只有 3-4 条记录。这就是为什么我想加入他们。
【问题讨论】:
标签: java hibernate jpa spring-data-jpa spring-data