Java Hibernate org.hibernate.LazyInitializationException:未能延迟初始化角色集合:

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20162077/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 23:35:58  来源:igfitidea点击:

Hibernate org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:

javaspringhibernatejpajersey

提问by J?cob

I have the below mentioned Entity classes, when I execute my application I am getting the following exception. Some of the other similar questions didn't solve the problem.

我有下面提到的实体类,当我执行我的应用程序时,我收到以下异常。其他一些类似的问题并没有解决问题。

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) 

How can I solve this issue?

我该如何解决这个问题?

Emp Entity

临时实体

@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;

Dept Entity

部门实体

@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

DAOImpl

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

Jersey RESTful service

Jersey 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;
 }

Spring applicationContext.xml

Spring 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>

采纳答案by J?cob

I have resolved the issue by adding the following in web.xml

我已经通过在 web.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>

courtesy hereand here

礼貌在这里这里

Thanks

谢谢

回答by kostja

If you would like to continue using FetchType.LAZYbut need access to the lazily loaded attributes for some queries, a portable solution would be to access the field and perform an operation on it while still within a transaction/session. I mention portability because AFAIK Hibernate offers at least one different approach to explicitly trigger loading that is not part of the JPA spec.

如果您想继续使用FetchType.LAZY但需要访问某些查询的延迟加载的属性,可移植的解决方案是访问该字段并在事务/会话中对其执行操作。我提到可移植性是因为 AFAIK Hibernate 提供了至少一种不同的方法来显式触发加载,这不是 JPA 规范的一部分。

Adapting your code, this could look like this:

调整您的代码,这可能如下所示:

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;
}

EDIT: Another portable alternative would be to use fetch joins in the query. Your Emp.findAllEmployeesquery could look like this:

编辑:另一种可移植的替代方法是在查询中使用获取连接。您的Emp.findAllEmployees查询可能如下所示:

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

Make it a left join if you have Emps without departments and departments without empDetNo

如果您有没有部门的 Emps 和没有 empDetNo 的部门,则将其设为左连接

回答by isnot2bad

The problem is that the scope of your database/JPA transaction only contains the service (which I assume is a stateless session bean) and does NOT contain the REST resource bean.

问题是你的数据库/JPA 事务的范围只包含服务(我假设它是一个无状态会话 bean)而不包含 REST 资源 bean。

  1. Web serverdispatches request to JAX-RS service
  2. JAX-RS servicecalls EJB Stateless Session Bean
  3. Transaction starts
  4. EJB Stateless Session Beanloads data from database (other beans might be involved)
  5. EJB Stateless Session Beanreturns result
  6. Transaction ends
  7. JAX-RS servicereturns result
  8. JAX-RS Producercreates XML out of List<Emp>and accesses field empDeptno.
  1. Web 服务器将请求分派到JAX-RS 服务
  2. JAX-RS 服务调用 EJB Stateless Session Bean
  3. 交易开始
  4. EJB 无状态会话 Bean从数据库加载数据(可能涉及其他 bean)
  5. EJB 无状态会话 Bean返回结果
  6. 交易结束
  7. JAX-RS 服务返回结果
  8. JAX-RS Producer创建 XMLList<Emp>并访问 field empDeptno

So when Jersey gets the list of Empto produce XML out of it, the transaction has already been closed. When now the field empDeptNois navigated, JPA tries to lazily load it, which fails as we're already outside a valid transaction/session.

因此,当 Jersey 获得Emp用于生成 XML的列表时,事务已经关闭。现在当该字段empDeptNo被导航时,JPA 尝试延迟加载它,这失败了,因为我们已经在一个有效的事务/会话之外。

You might try to extend the transaction scope to also contain your Jersey REST resource bean by making a stateless session bean out of it. Then it might be as follows:

您可以尝试通过创建无状态会话 bean 来扩展事务范围以包含您的 Jersey REST 资源 bean。那么它可能是这样的:

  1. Web serverdispatches request to JAX-RS service
  2. Transaction starts
  3. JAX-RS servicecalls EJB Stateless Session Bean
  4. EJB Stateless Session Beanloads data from database (other beans might be involved)
  5. EJB Stateless Session Beanreturns result
  6. JAX-RS servicereturns result
  7. JAX-RS Producercreates XML out of List<Emp>and accesses field empDeptno.
  8. Transaction ends
  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 Producer创建 XMLList<Emp>并访问 field empDeptno
  8. 交易结束

I'm not 100% sure, it might also be that step 8 comes BEFORE step 7, so the transaction might be closed before the producer does its job. If that's the case, this solution is simply wrong...

我不是 100% 确定,也可能是第 8 步出现在第 7 步之前,因此交易可能会在生产者完成其工作之前关闭。如果是这样的话,这个解决方案是完全错误的......

But I think you should simply try it...

但我认为你应该简单地尝试一下......