2013-11-23 109 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

相关问题