Java 为什么EclipseLink对同一个实体查询两次?
我对日食有一种奇怪的行为。在本例中,我将@BatchFetch(value=BatchFetchType.IN)添加到一个关系中,以从Student获得地址。当我查询两个学生的所有学生时,我正在检查EclipseLink生成的SQL,并且它两次查询同一地址和一个学生: EclipseLink 2.4.0版 首先,不带BatchFetch的查询:Java 为什么EclipseLink对同一个实体查询两次?,java,jpa,eclipselink,Java,Jpa,Eclipselink,我对日食有一种奇怪的行为。在本例中,我将@BatchFetch(value=BatchFetchType.IN)添加到一个关系中,以从Student获得地址。当我查询两个学生的所有学生时,我正在检查EclipseLink生成的SQL,并且它两次查询同一地址和一个学生: EclipseLink 2.4.0版 首先,不带BatchFetch的查询: SELECT ID, NAME FROM STUDENT SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS
SELECT ID, NAME FROM STUDENT
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [1]
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]
应为SQL,但现在当我添加BatchFetch到地址关系时,会生成以下内容:
SELECT ID, NAME FROM STUDENT
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID IN (?,?))
bind => [1, 2]
SELECT ID, NAME FROM STUDENT WHERE (ID = ?)
bind => [2]
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]
为什么EclipseLink在第一次查询“SELECT ID,NAME from student”(从学生处选择ID,姓名)中已经有了所有的学生,为什么EclipseLink在查询一个学生?如果它已经从SELECT ID,DESCRIPTION,student_ID from ADDRESS WHERE(1,2中的学生ID)中得到了地址,为什么它在查询地址
这种奇怪的行为只有在添加BatchFetch注释时才会发生
正如您所看到的,它两次查询学生和地址
SELECT ID, NAME FROM STUDENT WHERE (ID = ?)
bind => [2]
SELECT ID, DESCRIPTION, STUDENT_ID FROM ADDRESS WHERE (STUDENT_ID = ?)
bind => [2]
这些是课程:
Student.java:
@Entity
public class Student implements Serializable {
private Long id;
private String name;
private List<Address> addresses = new ArrayList<Address>();
private List<Classroom> classrooms = new ArrayList<Classroom>();
public Student() {
}
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQSTUDENTID")
@SequenceGenerator(name="SEQSTUDENTID", sequenceName="SEQSTUDENTID", allocationSize=1)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy="student", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@BatchFetch(value=BatchFetchType.IN)
public List<Address> getAddresses() {
return addresses;
}
public void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
@ManyToMany(mappedBy="students", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
public List<Classroom> getClassrooms() {
return classrooms;
}
public void setClassrooms(List<Classroom> classrooms) {
this.classrooms = classrooms;
}
}
@Entity
public class Address implements Serializable {
private Long id;
private Student student;
private String description;
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQADDRESSID")
@SequenceGenerator(name="SEQADDRESSID", sequenceName="SEQADDRESSID", allocationSize=1)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/META-INF/application-context-root.xml"})
@Transactional
public class TestingFetch {
@PersistenceContext
private EntityManager entityManager;
private Student student1;
private Student student2;
@Before
public void setUp() {
List<Student> students = new ArrayList<Student>();
student1 = new Student();
student1.setName("Alfredo Osorio");
Address student1Address1 = new Address();
student1Address1.setDescription("FirstAddressStudent1");
student1Address1.setStudent(student1);
student1.getAddresses().add(student1Address1);
Address student1Address2 = new Address();
student1Address2.setDescription("SecondAddressStudent1");
student1Address2.setStudent(student1);
student1.getAddresses().add(student1Address2);
students.add(student1);
student2 = new Student();
student2.setName("Jorge Ramirez");
students.add(student2);
Address student2Address1 = new Address();
student2Address1.setDescription("FirstAddressstudent2");
student2Address1.setStudent(student2);
student2.getAddresses().add(student2Address1);
Address student2Address2 = new Address();
student2Address2.setDescription("SecondAddressstudent2");
student2Address2.setStudent(student2);
student2.getAddresses().add(student2Address2);
Classroom classroom1 = new Classroom();
classroom1.setName("Mathematics");
Classroom classroom2 = new Classroom();
classroom2.setName("Physics");
Classroom classroom3 = new Classroom();
classroom3.setName("Chemistry");
classroom1.getStudents().add(student1);
student1.getClassrooms().add(classroom1);
classroom1.getStudents().add(student2);
student2.getClassrooms().add(classroom1);
classroom2.getStudents().add(student1);
student1.getClassrooms().add(classroom2);
classroom3.getStudents().add(student2);
student2.getClassrooms().add(classroom3);
for (Student student : students) {
entityManager.persist(student);
}
entityManager.flush();
entityManager.clear();
}
@Test
public void testFetch1() {
String jpql = "select m from Student m";
Query query = entityManager.createQuery(jpql);
List<Student> list = (List<Student>)query.getResultList();
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({/META-INF/application context root.xml})
@交易的
公共类测试获取{
@持久上下文
私人实体管理者实体管理者;
私立学生1;
私立学生2名;
@以前
公共作废设置(){
List students=new ArrayList();
student1=新学生();
学生1.集合名(“Alfredo Osorio”);
Address student1Address1=新地址();
student1Address1.setDescription(“FirstAddressStudent1”);
学生1地址1。设置学生(学生1);
student1.getAddresses().add(student1Address1);
Address student1Address2=新地址();
Student1地址2.setDescription(“第二地址Student1”);
学生1地址2.设置学生(学生1);
student1.getAddresses().add(student1Address2);
学生。添加(学生1);
student2=新学生();
学生2.教名(“豪尔赫·拉米雷斯”);
学生。添加(学生2);
Address student2Address1=新地址();
student2Address1.setDescription(“FirstAddressstudent2”);
学生2地址1.设置学生(学生2);
student2.getAddresses().add(student2Address1);
Address student2Address2=新地址();
student2Address2.setDescription(“第二个地址Student2”);
学生2地址2.设置学生(学生2);
student2.getAddresses().add(student2Address2);
教室教室1=新教室();
教室1.集合名(“数学”);
教室教室2=新教室();
教室2.设置名称(“物理”);
教室教室3=新教室();
教室3.设置名称(“化学”);
classroom1.getStudents().add(student1);
student1.getquestions().add(classroom1);
classroom1.getStudents().add(student2);
student2.getquestions().add(classroom1);
classroom2.getStudents().add(student1);
student1.getquestions().add(classroom2);
classroom3.getStudents().add(student2);
student2.getquestions().add(classroom3);
用于(学生:学生){
坚持(学生);
}
entityManager.flush();
entityManager.clear();
}
@试验
公共void testFetch1(){
String jpql=“从学生m中选择m”;
Query Query=entityManager.createQuery(jpql);
List=(List)query.getResultList();
}
}
从你们的关系中移除渴望。“渴望”导致在完成第一个查询之前执行批处理查询,从而导致额外的选择
(即,在构建第一个学生时,批处理查询会选择所有地址,并且该地址有一个返回给学生的多个地址,这也会导致查询。是的,但是EclipseLink不应该在再次执行查询之前检查它在持久性上下文中是否已经有该实体吗?而且我很难更改获取该实体的类型,因为它可能会对发送到视图的分离实体产生令人讨厌的副作用。除了更改获取类型之外,还有其他方法解决此问题吗?这是一个错误吗?我应该报告此错误吗?问题是尚未在持久性上下文中的第二个学生,当渴望触发batc时,它仍在构建第一个对象h query您可以使用加载组强制获取关系,而不是使用EAGER;如果必须使用EAGER,您还可以使用join fetch而不是batch fetch