Hibernate org.hibernate.LazyInitializationException:懒得初始化角色集合:

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

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

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

DAOImpl

 @Override public List 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 getEmployees() { List emp = new ArrayList(); emp.addAll(getEmployeeService().findAllEmployees()); return emp; } 

Spring applicationContext.xml

                               

我已通过在web.xml中添加以下内容来解决此问题

  OpenEntityManagerInViewFilter org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter   OpenEntityManagerInViewFilter /*  

在这里和这里礼貌

谢谢

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

  1. Web服务器将请求分派给JAX-RS服务
  2. JAX-RS服务调用EJB无状态会话Bean
  3. 交易开始
  4. EJB无状态会话Bean从数据库加载数据(可能涉及其他bean)
  5. EJB无状态会话Bean返回结果
  6. 交易结束
  7. JAX-RS服务返回结果
  8. JAX-RS ProducerList创建XML并访问empDeptno字段。

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

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

  1. Web服务器将请求分派给JAX-RS服务
  2. 交易开始
  3. JAX-RS服务调用EJB无状态会话Bean
  4. EJB无状态会话Bean从数据库加载数据(可能涉及其他bean)
  5. EJB无状态会话Bean返回结果
  6. JAX-RS服务返回结果
  7. JAX-RS ProducerList创建XML并访问empDeptno字段。
  8. 交易结束

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

但我认为你应该只是尝试一下……

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

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

 public List findAllEmployees() { List employees = getEntityManager().createNamedQuery("Emp.findAllEmployees", Emp.class).getResultList(); //trigger loading of attributes for(Emp emp: employees){ emp.getDeptNo().getEmpDetNo().size(); } return employees; } 

编辑:另一种便携式替代方法是在查询中使用fetch join。 您的Emp.findAllEmployees查询可能如下所示:

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

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