1

我正在尝试查询a person by id,并且在下面的架构中,我在人和学校之间有一个@OneToMany参考AddressPerson一个参考。ManyToOne我使用命名查询和查询提示来获得这个简单任务的最佳性能查询,但是查看堆栈跟踪(发布的相关部分),当我想要的只是 id 的人员对象时,EclipseLink 会生成三个 Select 语句?使用急切获取会降低性能,所以我的问题是如何简单地使用 JPQL 创建一个查询,该查询通过 ID 获取一个人对象而不引用其他类?

@NamedQuery(
        name="findPersonById",
        query="SELECT p FROM Person as p  WHERE p.id = :id",
                hints={@QueryHint(name="eclipselink.batch.type", value="JOIN"),
                @QueryHint(name="eclipselink.batch", value="p.address")
                }
)
public class Person {

    @Id
    @TableGenerator(name = "TABLE_GEN", table = "PERSON_SEQUENCE_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PER_SEQ", allocationSize = 1, initialValue = 10000)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
    @Column(name = "personID")
    private Long id;

    @ManyToOne(cascade = CascadeType.PERSIST,fetch = FetchType.LAZY)
    @JoinColumn(name = "addressID")
    private Address address;

    @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY)
    @JoinColumn(name = "schoolID")
    private School school;

}

地址实体

public class Address {


    @Id
    @TableGenerator(name = "ADDRESS_TABLE_GEN", table = "ADDRESS_SEQUENCE_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ADDR_SEQ", allocationSize = 1, initialValue = 1)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "ADDRESS_TABLE_GEN")
    @Column(name = "addressID")
    private Long id;


    @OneToMany(cascade = CascadeType.ALL, mappedBy = "address")
    private Set<Person> persons = new HashSet<Person>();

命名查询实现

public Person getPersonQueryBatch(Long id){

    EntityManager entityManager = factory.createEntityManager();
    Person person = null;

    try {

         List<Person> results = entityManager.createNamedQuery("findPersonById")
        .setParameter("id", id)
        .getResultList();
        if(!results.isEmpty()){
            // ignores multiple results
            person = results.get(0);
        }
    } catch (NoResultException e) {
        e.printStackTrace();
    }

    entityManager.close();
    return person;

}

堆栈跟踪:它搜索addressID等于 1 的最后一位正在挂起

[EL Finest]: jpa: 2012-06-26 20:47:29.78--ServerSession(1259621282)--Thread(Thread[main,5,main])--Begin deploying Persistence Unit persistenceUnit; session file:/Users/warz07/Documents/workspace-sts-2.8.0.RELEASE/dugsimanager/target/classes/_persistenceUnit; state Deployed; factoryCount 2
[EL Finest]: jpa: 2012-06-26 20:47:29.781--ServerSession(1259621282)--Thread(Thread[main,5,main])--End deploying Persistence Unit persistenceUnit; session file:/Users/warz07/Documents/workspace-sts-2.8.0.RELEASE/dugsimanager/target/classes/_persistenceUnit; state Deployed; factoryCount 2
[EL Finer]: connection: 2012-06-26 20:47:29.787--ServerSession(1259621282)--Thread(Thread[main,5,main])--client acquired: 67158058
[EL Finer]: transaction: 2012-06-26 20:47:29.788--ClientSession(67158058)--Thread(Thread[main,5,main])--acquire unit of work: 1296566131
[EL Finest]: query: 2012-06-26 20:47:29.788--UnitOfWork(1296566131)--Thread(Thread[main,5,main])--Execute query ReadObjectQuery(name="findPersonById" referenceClass=Person sql="SELECT personID, TYPE, DATEADDED, FIRSTNAME, LASTNAME, MIDDLENAME, ACTIVE, BIRTHDAY, EMAILADDRESS, GENDER, IMAGEPATH, MARITAL, PRIMARYTELEPHONE, SECONDARYTELEPHONE, version, addressID, schoolID, ETHNICITY, HISPANIC, MAJOR, NATIVELANGUAGE, RELIGIOUSAFFILIATION, studentId FROM PERSON WHERE (personID = ?)")
[EL Finest]: connection: 2012-06-26 20:47:29.789--ServerSession(1259621282)--Connection(65769329)--Thread(Thread[main,5,main])--Connection acquired from connection pool [read].
[EL Finest]: connection: 2012-06-26 20:47:29.789--ServerSession(1259621282)--Thread(Thread[main,5,main])--reconnecting to external connection pool
[EL Fine]: sql: 2012-06-26 20:47:29.79--ServerSession(1259621282)--Connection(1578517945)--Thread(Thread[main,5,main])--SELECT personID, TYPE, DATEADDED, FIRSTNAME, LASTNAME, MIDDLENAME, ACTIVE, BIRTHDAY, EMAILADDRESS, GENDER, IMAGEPATH, MARITAL, PRIMARYTELEPHONE, SECONDARYTELEPHONE, version, addressID, schoolID, ETHNICITY, HISPANIC, MAJOR, NATIVELANGUAGE, RELIGIOUSAFFILIATION, studentId FROM PERSON WHERE (personID = ?)
    bind => [10000]
[EL Finest]: connection: 2012-06-26 20:47:29.798--ServerSession(1259621282)--Connection(65769329)--Thread(Thread[main,5,main])--Connection released to connection pool [read].
2012-06-26 20:47:29,802 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Student': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Person.entityManager
2012-06-26 20:47:29,803 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
[EL Finest]: query: 2012-06-26 20:47:29.821--ServerSession(1259621282)--Thread(Thread[main,5,main])--Execute query ReadAllQuery(name="address" referenceClass=Address sql="SELECT DISTINCT t0.addressID, t0.CITY, t0.COUNTRY, t0.STATE_US, t0.STREETADDRESS, t0.STREETADDRESS2, t0.version, t0.ZIPCODE FROM ADDRESS t0, PERSON t1 WHERE ((t0.addressID = t1.addressID) AND (t1.personID = ?))")
[EL Finest]: connection: 2012-06-26 20:47:29.821--ServerSession(1259621282)--Connection(420965983)--Thread(Thread[main,5,main])--Connection acquired from connection pool [read].
[EL Finest]: connection: 2012-06-26 20:47:29.821--ServerSession(1259621282)--Thread(Thread[main,5,main])--reconnecting to external connection pool
[EL Fine]: sql: 2012-06-26 20:47:29.822--ServerSession(1259621282)--Connection(1364143063)--Thread(Thread[main,5,main])--SELECT DISTINCT t0.addressID, t0.CITY, t0.COUNTRY, t0.STATE_US, t0.STREETADDRESS, t0.STREETADDRESS2, t0.version, t0.ZIPCODE FROM ADDRESS t0, PERSON t1 WHERE ((t0.addressID = t1.addressID) AND (t1.personID = ?))
    bind => [10000]
[EL Finest]: connection: 2012-06-26 20:47:29.825--ServerSession(1259621282)--Connection(420965983)--Thread(Thread[main,5,main])--Connection released to connection pool [read].
2012-06-26 20:47:29,826 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Address': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Address.entityManager
2012-06-26 20:47:29,827 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
2012-06-26 20:47:29,830 [main] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Student': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Person.entityManager
2012-06-26 20:47:29,831 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
[EL Finest]: transaction: 2012-06-26 20:47:29.832--UnitOfWork(1296566131)--Thread(Thread[main,5,main])--[EL Finest]: query: 2012-06-26 20:47:29.844--ServerSession(1259621282)--Thread(Thread[main,5,main])--Execute query ReadAllQuery(name="persons" referenceClass=Person )
[EL Finest]: connection: 2012-06-26 20:47:29.845--ServerSession(1259621282)--Connection(36219749)--Thread(Thread[main,5,main])--Connection acquired from connection pool [read].
[EL Finest]: connection: 2012-06-26 20:47:29.845--ServerSession(1259621282)--Thread(Thread[main,5,main])--reconnecting to external connection pool
[EL Fine]: sql: 2012-06-26 20:47:29.845--ServerSession(1259621282)--Connection(1007449342)--Thread(Thread[main,5,main])--SELECT personID, TYPE, DATEADDED, FIRSTNAME, LASTNAME, MIDDLENAME, ACTIVE, BIRTHDAY, EMAILADDRESS, GENDER, IMAGEPATH, MARITAL, PRIMARYTELEPHONE, SECONDARYTELEPHONE, version, addressID, schoolID, ETHNICITY, HISPANIC, MAJOR, NATIVELANGUAGE, RELIGIOUSAFFILIATION, studentId FROM PERSON WHERE (addressID = ?)
    bind => [1] 

运行查询的测试用例

public void testSavingPersonSchool(){

        PersonService personService = new PersonService();
        System.out.println("here\n");
        Person cPerson = personService.getPersonQueryBatch(Long.valueOf("10000"));
        System.out.println("not here\n");
        School school = new School();
        Address address = new Address();
        address.setStreetAddress("eer street");
        address.setCity("hiokins");
        address.setZipCode("34343");
        address.setState_us("MN");
        address.setCountry("usa");

        school.setName("Maui");
        school.setDescription("Thinking of dropping a summer class?");
        school.setAddress(address);
        school.setPrimaryPhone("3242342342");
        school.setAdmissionsPhone("3242342342");
        school.setAdmissionsEmailAddress("ads@d.com");
        school.setActive(true);
        cPerson.setSchool(school);
        school.persist();

学生.java

package org.bixin.dugsi.domain;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.OneToMany;
import javax.persistence.PostPersist;
import javax.validation.constraints.NotNull;
import org.eclipse.persistence.annotations.BatchFetch;
import org.eclipse.persistence.annotations.BatchFetchType;
import org.eclipse.persistence.annotations.JoinFetch;
import org.eclipse.persistence.annotations.JoinFetchType;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooJpaActiveRecord
@DiscriminatorValue("S")
public class Student extends Person {

    @Basic
    @Column(name = "studentId")
    private String studentIdentifier;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "student", fetch = FetchType.LAZY)
    private Set<Registration> registrations = new HashSet<Registration>();

    @PostPersist
    public void generateCode() {
        studentIdentifier = ("S-000-");
    }
}
4

2 回答 2

1

从这些行:

2012-06-26 20:47:29,802 [main] 调试 org.springframework.beans.factory.annotation.InjectionMetadata - 处理 bean 'org.bixin.dugsi.domain.Student' 的注入方法:瞬态 javax.persistence 的 PersistenceElement。 EntityManager org.bixin.dugsi.domain.Person.entityManager

您似乎正在对实体类进行一些注入。需要查看实体的完整来源才能确定。尽管如此,如果你这样做..好吧..不要:)在每个实体上创建spring代理或执行DI是一种过大的杀伤力,也几乎肯定会破坏整个惰性初始化,因为Spring将在执行DI时访问ManyToOne集合,也为这些实体触发数据库加载。

作为旁注:您的实体不应包含业务逻辑,因此没有理由对它们进行任何依赖注入。

于 2012-06-27T02:35:24.480 回答
0

With the fetch set to LAZY access to the Person should not trigger queries to the address or school. Do you have weaving enabled (using agent or Java EE/Spring weaving)? You may need to enable dynamic weaving or use static weaving.

It may be something else is triggering the relationships, you could put a breakpoint, or dump the stack trace (using a SessionEvent) in the EclipseLink Session query execution.

Your batch fetch on the address does not make sense, batch fetching is for when the query returns many results, but you are finding by id. You could use a join fetch (in the JPQL or through the join fetch hint).

I'm not sure how this could hang, break the process to get the stack trace to see what it is waiting on.

于 2012-06-27T12:56:47.753 回答