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。
- Web服务器将请求分派给JAX-RS服务
- JAX-RS服务调用EJB无状态会话Bean
- 交易开始
- EJB无状态会话Bean从数据库加载数据(可能涉及其他bean)
- EJB无状态会话Bean返回结果
- 交易结束
- JAX-RS服务返回结果
- JAX-RS Producer从
List
创建XML并访问empDeptno
字段。
因此,当Jersey获取Emp
列表以生成XML时,该事务已经被关闭。 当现在导航empDeptNo
字段时,JPA会尝试延迟加载它,因为我们已经在有效的事务/会话之外而失败了。
您可以尝试通过从中创建无状态会话bean来扩展事务范围以包含Jersey REST资源bean。 那么它可能如下:
- Web服务器将请求分派给JAX-RS服务
- 交易开始
- JAX-RS服务调用EJB无状态会话Bean
- EJB无状态会话Bean从数据库加载数据(可能涉及其他bean)
- EJB无状态会话Bean返回结果
- JAX-RS服务返回结果
- JAX-RS Producer从
List
创建XML并访问empDeptno
字段。 - 交易结束
我不是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,请将其设为左连接