0

EclipseLinkで奇妙な動作が発生します。@BatchFetch(value = BatchFetchType.IN)を、この場合は学生からの住所への関係に追加しました。2人のすべての学生にクエリを実行し、同じアドレスと1人の学生に2回クエリを実行すると、EclipseLinkによって生成されたSQLをチェックしています。

EclipseLinkバージョン2.4.0

まず、BatchFetchを使用しないクエリ:

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とAddressの関係を追加すると、次のように生成されます。

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が最初のクエリ「SELECTID、NAME FROM STUDENT」からすべての学生をすでに持っている場合、なぜEclipseLinkは学生をクエリするのですか。また、SELECT ID、DESCRIPTION、STUDENT_ID FROM ADDRESS WHERE(STUDENT_ID IN(1,2))この奇妙な動作は、BatchFetchアノテーションを追加した場合にのみ発生します。

ご覧のとおり、StudentとAddressの2倍のクエリを実行しています。

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;
    }

}

Address.java:

@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();
    }
}
4

1 に答える 1

1

あなたの関係からEAGERを取り除きます。EAGER により、最初のクエリが実行される前にバッチ クエリが実行され、余分な選択が発生します。

(つまり、最初の学生を構築している間、バッチクエリはすべてのアドレスを選択し、アドレスには、EAGER でもある学生に戻る ManyToOne があるため、クエリが発生します。

于 2012-09-10T17:50:04.907 に答える