2012-08-27 24 views
0

首先是一些信息:LazyInitializationException中的預先抓取(分離)收集

  • 我使用:
    • 春3.1.1.RELEASE
    • 休眠4.1.5.SP1
    • JSF 2.0 ?
    • 的OpenSessionInViewFilter(org.springframework.orm.hibernate4.support.OpenSessionInViewFilter)
    • PrimeFaces 3.3.1
    • Lombok的0.11.2
    • 的JBoss 7.1.1.Final

短版本:

當我的實體Emloyee變得分離(一個d因此它也是熱切地獲取Location的集合),我不能撥打Employee.getLocations().add()而沒有得到LazyInitializationException。使用非基於JPA的集合充當傳輸對象的作品。

長版本:

我有了的Location個集合的實體Employee

@Data 
@EqualsAndHashCode(callSuper = true, of = {}) 
@ToString(callSuper = true, of = {}) 
@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
public class Employee extends Person 
{ 
    @ManyToMany 
    @JoinTable(name = "location_employee", 
      joinColumns = @JoinColumn(name = "employee_id", 
        referencedColumnName = "id"), 
      inverseJoinColumns = @JoinColumn(name = "location_id", 
        referencedColumnName = "id")) 
    private Set<Location> locations = new HashSet<Location>(); 
} 

Employee延伸從Person其中有一些字符串,如姓名等,但這些都是不相關。

@Data 
@EqualsAndHashCode(of = "id") 
@ToString(of = { "id", "name" }) 
@Entity 
@Inheritance(strategy = InheritanceType.JOINED) 
public class Person 
{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Setter(AccessLevel.NONE) 
    private Long id; 

    private String name; 
} 

Location類也很簡單:

@Data 
@EqualsAndHashCode(of = "id") 
@ToString(of = { "id", "name" }) 
@Entity 
public class Location 
{ 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Setter(AccessLevel.NONE) 
    private Long   id; 

    private String   name; 
    @ManyToMany 
    @JoinTable(name = "location_employee", 
      joinColumns = @JoinColumn(name = "location_id", 
        referencedColumnName = "id"), 
      inverseJoinColumns = @JoinColumn(name = "employee_id", 
        referencedColumnName = "id")) 
    private Set<Employee> employees = new HashSet<Employee>(); 
} 

所有藏品都默認懶惰。但是,在我的JSF頁面中,我想將Location s添加到現有的Employee。要使用下面的支持bean爲此,我渴望負載我Employee

@Named 
@Scope("view") 
public class BackingBean 
{ 
    @Inject 
    private EmployeeDAO employeeDAO; 
    private Employee  employeeFull; 
    @Inject 
    private LocationDAO locationDAO; 
    private List<Location> locations; 

    public Employee getSelectedEmployeeFull() 
    { 
     if (selectedEmployeeFull == null) 
     { 
      selectedEmployeeFull = employeeDAO.getEagerById(1L); 
     } 
     return selectedEmployeeFull; 
    } 

    public void setEmployeeFull(Employee e) 
    { 
     employeeFull = e; 
    } 

    public List<Location> getLocations() 
    { 
     if (locations == null) 
     { 
      locations = locationDAO.getAll() 
     } 
     return locations; 
    } 

    //... 
} 

EmployeeDAO類包括貪婪加載查詢:

@Named 
public class EmployeeDAO 
{ 
    @Inject 
    private SessionFactory sessionFactory; 

    @Transactional(readOnly = true) 
    public Employee getEager(Long id) 
    { 
     Query q = sessionFactory.getCurrentSession().createQuery("select e from Employee e join fetch e.locations where e.id = :id"); 
     q.setParameter("id", id); 
     try 
     { 
      return (Employee) q.uniqueResult(); 
     } 
     catch (NonUniqueObjectException ex) 
     { 
      //Exception logging/handling 
      return null; 
     } 
    } 
} 

在我的JSF我有下面的代碼片段:

<p:dialog dynamic="true"> 
    <h:form> 
     <p:selectCheckboxMenu label="Locations" value="#{employeeBean.employeeFull.locations}"> 
      <f:selectItems var="location" itemLabel="#{location.name}" value="#{employeeBean.locations}" /> 
     </p:selectCheckboxMenu> 

     <p:commandButton value="save" action="#{employeeBean.update}"/> 
    </h:form> 
</p:dialog> 

當我打開對話框時,它會加載employeeFull屬性,並用Location s和m填充selectCheckboxMenu方框Location s Employee已經有了。

然而,當我點擊保存按鈕(在不改變任何東西)和表單被提交的Employee.locations收集trows一個LazyInitializationException

09:36:42,633 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (http-localhost-127.0.0.1-8080-1) failed to lazily initialize a collection, no session or session was closed: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed 
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:394) [hibernate-core-4.1.5.SP1.jar:4.1.5.SP1] 
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:386) [hibernate-core-4.1.5.SP1.jar:4.1.5.SP1] 
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:379) [hibernate-core-4.1.5.SP1.jar:4.1.5.SP1] 
    at org.hibernate.collection.internal.PersistentSet.add(PersistentSet.java:206) [hibernate-core-4.1.5.SP1.jar:4.1.5.SP1] 
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel(MenuRenderer.java:382) [jsf-impl-2.1.7-jbossorg-2.jar:] 
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValue(MenuRenderer.java:129) [jsf-impl-2.1.7-jbossorg-2.jar:] 
    at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:315) [jsf-impl-2.1.7-jbossorg-2.jar:] 
    at org.primefaces.component.selectcheckboxmenu.SelectCheckboxMenuRenderer.getConvertedValue(SelectCheckboxMenuRenderer.java:34) [primefaces-3.3.1.jar:] 
    at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIInput.validate(UIInput.java:960) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1233) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIInput.processValidators(UIInput.java:698) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIForm.processValidators(UIForm.java:253) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at org.primefaces.component.dialog.Dialog.processValidators(Dialog.java:359) [primefaces-3.3.1.jar:] 
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76) [jsf-impl-2.1.7-jbossorg-2.jar:] 
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:] 
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:] 
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] 
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79) [primefaces-3.3.1.jar:] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:322) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter.doFilter(DefaultLoginPageGeneratingFilter.java:91) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:182) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:184) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:155) [spring-security-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] 
    at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:119) [spring-orm-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE] 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:] 
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final] 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:] 
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:] 
    at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_31] 

EmployeeBean.update方法不會被調用爲它設置的斷點永遠不會打。

現在爲盛大結局:我怎樣才能防止這 LazyInitializationException

編輯

我已經創建了一個解決辦法,但這可能不是最好的解決辦法:

在JSF頁面:

<p:dialog dynamic="true" onShow="loadSelectedEmployee()"> 
    <h:form> 
     <p:remoteCommand action="#{employeeBean.loadSelectedEmployee}" name="loadSelectedEmployee" update=":editEmployeeDialogContent" /> 
    </h:form> 
    <p:outputPanel layout="block" id="editEmployeeDialogContent"> 
     <h:form rendered="#{employeeBean.selectedEmployeeLoaded}"> 
      <p:selectCheckboxMenu label="Locations" value="#{employeeBean.selectedEmployee.locations}"> 
       <f:selectItems var="location" itemLabel="#{location.name}" value="#{employeeBean.locations}" /> 
      </p:selectCheckboxMenu> 

      <p:commandButton value="save" action="#{employeeBean.update}"/> 
     </h:form> 
    </p:outputPanel> 
</p:dialog> 

在支持bean:

public void loadSelectedEmployee() 
{ 
    if (!selectedEmployeeLoaded) 
    { 
     selectedEmployee.setLocations(locationManager 
       .getByEmployee(selectedEmployee)); 
     selectedEmployee.setRoles(roleManager 
       .getByEmployee(selectedEmployee)); 
     selectedEmployeeLoaded = true; 
    } 
} 
+0

嘗試通過移除轉換器等不必要的東西來追蹤問題。 – JMelnik

+0

@JMelnik我刪除了轉換器,堆棧跟蹤僅在第4行到第12行之間不同。當JSF調用PersistentBag.add()方法,而袋子斷開。 – siebz0r

+0

嘗試使用hibernate進行檢查,如果集合已初始化,請將其放在代碼中的某處(look stacktrace)。如何檢查:http://stackoverflow.com/a/4306498/685962 – JMelnik

回答

0

如果y如果對與標記的「渴望」沒有關係的實體做HQL,將繼續「懶惰」的品牌,並嘗試在「獲得」時查詢數據。

對於這種情況迫使初始化的關係的一個例子是:

Hibernate.initialize(e.getLocations()); 

集成:

@Transactional(readOnly = true) 
public Employee getEager(Long id) 
{ 
    Query q = sessionFactory.getCurrentSession().createQuery("select e from Employee e join fetch e.locations where e.id = :id"); 
    q.setParameter("id", id); 
    try 
    { 
     final Employee e = (Employee) q.uniqueResult(); 
     if(e != null){ 
      Hibernate.initialize(e.getLocations()); 
     } 
     return e; 

    } 
    catch (NonUniqueObjectException ex) 
    { 
     //Exception logging/handling 
     return null; 
    } 
} 

Regads,

1

這是definitly一個錯誤,我想無論是在Primefaces或者在Jboss-jsf-api-2.1中。 我可以直接在控制器中修改PersistenSet,因此它的definitly預先加載,但是當綁定到JSF組件(我使用Primefaces selectCheckboxMenu)時,它也會拋出LazyInitalizationException。