2013-11-23 159 views
6

我有下面提到的實體類,當我執行我的應用程序時我收到以下異常。其他一些類似的問題並沒有解決問題。Hibernate org.hibernate.LazyInitializationException:未能懶惰地初始化一個角色集合:

WARNING: StandardWrapperValve[jersey-serlvet]: PWC1406: Servlet.service() 
for servlet jersey-serlvet threw exception 
org.hibernate.LazyInitializationException: failed to lazily initialize 
a collection of role: test.entity.Dept.empDeptno, no session 
or session was closed 
at org.hibernate.collection.internal.AbstractPersistentCollection. 
throwLazyInitializationException(AbstractPersistentCollection.java:393) 
     at org.hibernate.collection.internal.AbstractPersistentCollection. 
throwLazyInitializationExceptionIfNotConnected 
(AbstractPersistentCollection.java:385) 
    at org.hibernate.collection.internal.AbstractPersistentCollection. 
initialize(AbstractPersistentCollection.java:378) 

我該如何解決這個問題?

的Emp實體

@Entity 
@Table(name = "EMP", schema = "SCOTT" 
) 
@XmlRootElement 
@NamedQueries({ 
    @NamedQuery(name = "Emp.findAllEmployees", query = "select e from Emp e left 
    join fetch e.deptNo order by e.empno desc") 
}) 
public class Emp implements java.io.Serializable { 
@Id 
@Column(name = "EMPNO", unique = true, nullable = false, precision = 4, 
scale = 0) 
private short empno; 
@ManyToOne 
@JoinColumn(name = "DEPTNO", referencedColumnName = "DEPTNO") 
private Dept deptNo; 

部門實體

@Entity 
@Table(name = "DEPT", schema = "SCOTT" 
) 
@XmlRootElement 
public class Dept implements java.io.Serializable { 
@Id 
@Column(name = "DEPTNO", unique = true, nullable = false, precision = 2, 
scale = 0) 
private short deptno; 
@OneToMany(fetch=FetchType.LAZY,mappedBy = "deptNo") 
private Set<Emp> empDeptno; 

DAOImpl

@Override 
public List<Emp> findAllEmployees() { 
    return getEntityManager().createNamedQuery("Emp.findAllEmployees", 
Emp.class).getResultList(); 
} 

新澤西RESTful服務

@Component 
@Path("/employee") 
public class EmployeeRestService { 

@Autowired 
EmployeeService employeeService; 

@GET 
@Produces({MediaType.APPLICATION_JSON}) 
public List<Emp> getEmployees() { 
List<Emp> emp = new ArrayList<Emp>(); 
emp.addAll(getEmployeeService().findAllEmployees()); 
return emp; 
} 

春天的applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd" 
> 
    <!-- Data Source Declaration -->  
    <bean id="DataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> 
     <property name="jndiName" value="jdbc/scottDS"/> 
    </bean> 

    <context:component-scan base-package="net.test" /> 
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> 
    <bean id="entityManagerFactory" 
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="dataSource" ref="DataSource" /> 
     <property name="packagesToScan" value="net.test" /> 
     <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <property name="showSql" value="false" /> 
       <property name="generateDdl" value="false" /> 
       <property name="databasePlatform" value="${jdbc.dialectClass}" /> 
      </bean> 
     </property> 
    </bean> 
    <bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" /> 
    <!-- Transaction Config --> 
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 
    <tx:annotation-driven transaction-manager="transactionManager"/>   
    <context:annotation-config/> 
    <bean id="hibernateStatisticsMBean" class="org.hibernate.jmx.StatisticsService"> 
     <property name="statisticsEnabled" value="true" /> 
     <property name="sessionFactory" value="#{entityManagerFactory.sessionFactory}" /> 
    </bean> 
</beans> 
+0

你試圖訪問該集合,而會話仍然可用?你可能仍然會收到一個代理對象,所以請調用一個簡單的操作,比如'size()' – kostja

+0

@kostja我從RESTful服務調用方法,我通過編輯我的問題發佈了我的RESTful服務和DAOImpl代碼片段。 – user75ponic

+0

您可能需要將'empDetno'字段的'FetchType'更改爲'EAGER'。一個不太乾淨的解決方案是通過訪問它來觸發加載'findAllEmployees'方法中的'empDet'集合。 – kostja

回答

9

我已經通過添加網頁下面的解決了這個問題。XML

<filter> 
<filter-name>OpenEntityManagerInViewFilter</filter-name> 
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> 
</filter> 
<filter-mapping> 
<filter-name>OpenEntityManagerInViewFilter</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 

禮貌herehere

感謝

2

如果你想繼續使用FetchType.LAZY但需要訪問一些查詢延遲加載的屬性,便攜式解決方案將是在仍處於事務/會話內時訪問該字段並對其執行操作。我提到了可移植性,因爲AFAIK Hibernate至少提供了一種不同的方法來顯式觸發不屬於JPA規範的加載。

適應你的代碼,這可能是這樣的:

public List<Emp> findAllEmployees() { 
    List<Emp> employees = getEntityManager().createNamedQuery("Emp.findAllEmployees", 
    Emp.class).getResultList(); 

    //trigger loading of attributes 
    for(Emp emp: employees){ 
    emp.getDeptNo().getEmpDetNo().size(); 
    } 
    return employees; 
} 

編輯:另一種便攜式替代方法是使用取聯接查詢。你Emp.findAllEmployees查詢看起來是這樣的:

SELECT e FROM Emp e JOIN FETCH e.dept.empDetno 

使它成爲一個左連接,如果你有EMPS沒有部門和部門不empDetNo

+0

我有一個問題,empDeptno是在部門實體,而不是在Emp Entity中,第二種選擇是我已經爲我的查詢獲取連接。 – user75ponic

+0

@Polppan對不起,匆匆讀過這個問題。我想你可以通過導航擴展獲取連接。相應地編輯了答案。 OTOH優化交易分界,如isnot2bad表明可能是更好的方法。 – kostja

+0

感謝您的幫助,我在回答中解決了這個問題。 – user75ponic

5

的問題是,你的數據庫/ JPA事務的範圍只包含服務(我認爲它是一個無狀態的會話bean)並且不包含REST資源bean。

  1. Web服務器調度請求JAX-RS服務
  2. JAX-RS服務調用EJB Stateless Session Bean的
  3. 交易開始
  4. EJB無狀態會話Bean負荷來自數據庫的數據(可能涉及其他豆類)
  5. EJB無狀態會話Bean返回結果
  6. 交易結束
  7. JAX-RS服務返回結果
  8. JAX-RS生產者創建XML的List<Emp>並訪問現場empDeptno

因此,當澤西從Emp列表中產生XML時,交易已經關閉。當現在導航字段empDeptNo時,JPA試圖延遲加載它,由於我們已經在有效的事務/會話之外,JPA試圖失敗。

您可能會嘗試通過將無狀態會話Bean取出來擴展事務範圍以包含Jersey REST資源bean。然後,它可能如下:

  1. Web服務器調度請求JAX-RS服務
  2. 交易開始
  3. JAX-RS服務調用EJB Stateless Session Bean的
  4. EJB無狀態會話Bean從數據庫加載數據(可能涉及其他bean)
  5. EJB無狀態會話Bean返回結果
  6. JAX-RS服務返回結果
  7. JAX-RS生產者創建XML的List<Emp>並訪問現場empDeptno
  8. 交易結束

我不是100%肯定,這也可能是第8步到來之前第7步,所以生產商,它的工作之前,該交易可能會被關閉。如果是這樣的話,這個解決方案是完全錯誤的......

但我認爲你應該簡單地嘗試...

+0

你的意思是這樣的嗎? http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-45.html – user75ponic

+0

順便說一句,我使用的是彈簧 – user75ponic

+0

是的!但是在那裏他們不使用延遲加載,所以它仍然不清楚(對我而言),如果因爲序列化在事務範圍內或因爲要序列化的所有數據已經​​可用而工作。也許有人可以澄清這一點! – isnot2bad

相關問題