我有很多关于hibernate会话的问题,因为我对它们一直存在问题。
我正在使用Spring 3.1.1和Hibernate 4.1.3。
这里首先是我正在研究的类图。
代码类:
public class Equipement {
@ManyToOne(fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
public getOffice(){
return office ;
}
public class Office {
@ManyToOne(fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
public getService(){
return service ;
}
public class Service {
@ManyToOne(fetch = FetchType.LAZY)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
public getDepartement(){
return departement ;
}
以下是我加载所有设备的方法。
public class HibernateEquipementDao{
@SuppressWarnings("unchecked")
public List<Equipement> getAll() {
return sessionFactory.getCurrentSession().createQuery("from Equipement").list() ;
}
}
假设我将所有设备加载到List<Equipement> allEquipements
中,并希望例如仅使用某些服务或某些部门的设备来填充我的视图。
List<Equipement> aListOfEquipements = new ArrayList<Equipement>() ;
for(Equipement equipement : allEquipements)
if(equipement.getOffice().getService().getName().equals("name"))
aListOfEquipements.add(equipement) ;
我可以随时随地这样做吗?名为当前的会话始终处于活动状态? 有时我得到那个例外。 org.hibernate.LazyInitializationException:无法初始化代理 - 无会话
这让我问我的EquipementDao使用的当前会话在哪里?
当我想获得设备的部门时,有没有办法打开会话?
还是有另一种方法可以继续?如何管理会话以及如何加载我的所有Equipements并访问其他实体而没有任何问题?
答案 0 :(得分:3)
为服务添加图层,我知道这个名字在你的情况下不是那么幸运,但是在这一层你将拥有负责你的逻辑的类。
一些原型:
public class EquipmentService {
@Inject
private HibernateEquipementDao dao;
@Transactional
public List<Equipement> doSomethingWithEquipmentWithoutLazyException(Equipment equipment){
List<Equipement> allEquipments = dao.getAll();
List<Equipement> aListOfEquipements = new ArrayList<Equipement>() ;
for(Equipement equipement : allEquipements) {
if(equipement.getOffice().getService().getName().equals("name")) {
aListOfEquipements.add(equipement) ;
}
}
return aListOfEquipments;
}
}
非常imporatan是注释:@Transactional
这意味着会话将在开始时打开并在方法结束时关闭,因此无法抛出LazyLoadingException。
关于Transactonal的一些有趣的帖子:Where does the @Transactional annotation belong?
答案 1 :(得分:3)
我已经看到了解决这个问题的两种方法。
<强> 1。在视图中打开会话:
您可以在视图中配置休眠设置打开会话。 如果以编程方式配置休眠,可以使用以下行:
jpaProperties.put(org.hibernate.cfg.Environment.ENABLE_LAZY_LOAD_NO_TRANS, true)
其他方式是在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>
这种方法会影响你的所有系统,并且可能对你的表现不利。
<强> 2。 FETCH JOIN:
您可以在查询中使用FETCH JOIN来强制hibernate加载数据,例如:
from Equipement e FETCH JOIN e.office
这种方法将更难做到(系统中的许多要点)并且要小心。
第3。查询返回后调用get方法:
在DAO中,您可以在查询返回后调用get方法。我不喜欢这种方式,但通常都会工作。
很高兴,我希望我帮助过你。
答案 2 :(得分:0)
对于大多数Web应用程序来说,使当前事务跨越整个请求是最简单且绝对合适的。最简单的方法是使用Filter启动事务并在请求结束时提交/回滚。在Spring / Hibernate中,这在View模式中称为Open Entity。 Spring通过org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter提供了一个过滤器实现。
使用此方法时,视图(即您的JSP)参与同一事务,不需要重新加载,并且在fetchtype LAZY关系的情况下也可以导航实体。