我遇到了一个非常有趣的场景。我知道n+1问题和FetchType.Eager和FetchMode.join。我有一个家长实体学校,它有2@onetomany儿童实体ie学生和教师。我需要所有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是在数据库上的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=?
我意识到join只有在我们使用id ie主键的情况下才有效,但我没有学校的主键。我有学校的名字,这是唯一的,索引,并需要学生实体和教师实体也。有没有办法在Hibernate中使用join来获得它们。我知道如果学生和老师的记录更多,那么它将是性能下降,但在我的情况下,它将最多只有3-4个记录。这就是我想加入他们所有人的原因。
>
不宜用fetchmode.join
映射一个实体的多个关联集合字段。这是为了避免笛卡尔积问题
。我很惊讶,即使在您通过id
选择时,它也进行了sql联接
当您获取ID
字段以外的学校时,hibernate不知道您将获取多少个学校,因此如果它执行联接获取而不是单独选择,它将以cartesian product问题
结束
假设你有10所学校,每所学校有20名教师和400名学生。如果hibernate进行了联接,它将不得不从DB带来80,000
(10*20*400
)记录。但是由于它执行单独的选择,它将带来4,210
(10+200+4000
)记录。即使在通过id
选择的情况下,也是420条
记录与8000条
记录
简短回答
不要使用join检索父实体及其多个关联集合,即使您找到了这样做的方法,因为性能会比多次选择差。
更新:
findbyschoolname
返回列表
,您可以将其更改为返回可选的学校)@Repository
public interface SchoolRepository extends JpaRepository<School, Integer> {
@Query("SELECT s from School s left join fetch s.teachers " +
"left join fetch s.students where s.schoolName = :name")
Optional<School> findBySchoolName(String name);
}
1、主模块和非主模块的定义 在 Python 函数中,如果一个函数调用了其他函数完成一项功能,我们称这个函数为主函数,如果一个函数没有调用其他函数,我们称这种函数为非主函数。主模块和非主模块的定义也类似,如果一个模块被直接使用,而没有被别人调用,我们称这个模块为主模块,如果一个模块被别人调用,我们称这个模块为非主模块。 2、name 属性 在 Python 中,有主模块和非主模块之分,当然,我们也
我使用的是Scala中的0.9Kafka Java客户机。 在中更改参数的方差可以解决这个问题吗?
我正在使用jOOQ为我的数据库表生成POJO。这很有效。 我有一个带有主键()和唯一键()的表。更新记录时,jOOQ使用主键。 我想通过使用唯一键而不是主键来更新记录。 https://github.com/jOOQ/jOOQ/blob/master/jOOQ/src/main/java/org/jooq/impl/UpdatableRecordImpl.java 本质上,我想用另一个键(第二个参
我试图在测试配置中使用@primary声明的测试期间覆盖Spring bean。一个声明位于src/main/java路径中,另一个声明位于src/test/java路径中。 从日志来看: o.s.b.f.s.DefaultListableBeanFactory-用不同的定义重写bean“SQS ConnectionFactory”的bean定义:替换[根bean:class[null];scop
我有一个包含数据的表,其中一个行需要存在于另一个表中。所以,我想要一个外键来保持引用的完整性。 但是,正如您所看到的,我的外键所指向的表,列不是PK。有没有一种方法来创建这个外键,或者可能有一种更好的方法来维护这个引用完整性?
所有api调用都应使用前缀为的url,并应由REST控制器处理。 所有其他URL应该只提供文件。我如何用Spring实现这一点?