EclipseLink延迟加载在引用类上挂起

时间:2012-06-27 01:57:09

标签: java jpa eclipselink lazy-loading

我正在尝试查询a person by id,并且在我的架构中,我在@OneToManyAddress之间有一个Person引用,并在{}之间引用了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;

}

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

[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();

Student.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-");
    }
}

2 个答案:

答案 0 :(得分:1)

从以下几行:

  

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

您似乎正在对实体类进行一些注入。需要确定实体的完整来源。然而,如果你这样做..好吧..不要:)在每个实体上创建弹簧代理或做DI是一种矫枉过正,也几乎肯定会打败整个懒惰的初始化,因为Spring会访问在执行DI时,ManyToOne集合也会触发这些实体的数据库负载。

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

答案 1 :(得分:0)

将获取设置为LAZY访问Person不应该触发对地址或学校的查询。您是否启用了编织(使用代理或Java EE / Spring编织)?您可能需要启用动态编织或使用静态编织。

可能是触发关系的其他东西,您可以在EclipseLink会话查询执行中放置断点或转储堆栈跟踪(使用SessionEvent)。

您对地址的批量提取没有意义,批量提取适用于查询返回许多结果,但您通过id查找。您可以使用连接提取(在JPQL中或通过连接提取提示)。

我不确定它是如何挂起的,打破进程以获取堆栈跟踪以查看它正在等待的内容。