我有下面提到的Entity类,当我执行我的应用程序时,我收到以下异常。其他一些类似的问题并没有解决问题。
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<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;
}
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>
答案 0 :(得分:9)
我已在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>
由于
答案 1 :(得分:5)
问题是数据库/ JPA事务的范围只包含服务(我假设它是一个无状态会话bean),并且不包含REST资源bean。
List<Emp>
创建XML并访问字段empDeptno
。因此,当Jersey获取Emp
的列表以生成XML时,该事务已被关闭。当现在导航empDeptNo
字段时,JPA会尝试延迟加载它,因为我们已经在有效的事务/会话之外而失败了。
您可以尝试通过使用无状态会话bean来扩展事务范围以包含Jersey REST资源bean。然后它可能如下:
List<Emp>
创建XML并访问字段empDeptno
。我不是百分百肯定,也可能是步骤8之前的第8步,所以在生产者完成工作之前,交易可能会被关闭。如果是这种情况,这个解决方案就是错误的......
但我认为你应该只是尝试一下......
答案 2 :(得分: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;
}
编辑:另一种可移植的替代方法是在查询中使用fetch join。您的Emp.findAllEmployees
查询可能如下所示:
SELECT e FROM Emp e JOIN FETCH e.dept.empDetno
如果你没有没有empDetNo
的部门和部门的Emps,请将其设为左连接