在使用spring+hibernate时,我们对实体的一对多,多对一和多对多的关联实体进行获取值的时候通常会使用懒加载的方式。这样做的好处就是在我们需要关联对象的属性的时候,再去查询数据库,以至于我们不用一次查询很多的数据出来。


这样做经常会遇到一个异常:could not initialize proxy - no Session,本文就对此异常做各种处理方式的总结,结合实际需求去排除错误。


具体原因:使用懒加载方式,第一次获取主体对象后session已经关闭了,所以再去查询关联对象的属性时,没有session可以使用。


解决办法:

1. 使用fetch = FetchType.EAGER,即不使用懒加载,这样一次性就加载所有的属性,包括主体,关联实体。

好处:避免了懒加载session不存在。

坏处:丢失了懒加载的特性,一次加载数据过多对于程序效率有所影响。


2. 手动的控制session的开关。即自己打开一个session,并在使用完成以后手动的显示关闭该session。

Session session = sessionFactory.openSession();
// 通过session去查询对应的实体
User user = session.find(id);
// 获取关联对象
List<Role> roles = user.getRoles();
// 使用关联对象
for(Role role : roles) {
    System.out.println(role.getName());
}

好处:使用懒加载特性,需要时再获取。

坏处:需要手动的去控制session的开关。

应用场景:如spring容器启动时,需要去获取某对象关联的属性。或者Junit单元测试时。


3. 增加openSessionInView Filter,通过该filter来帮助实现session的开关控制。

<filter>
    <filter-name>openSessionInView</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>openSessionInView</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

好处:我们不需要手动的去控制session的开关。

坏处:对于像没有使用web容器,或者web容器并未启动,亦或者根本就没有发送请求即没有通过该Filter,则无法完成该功能。这种情况只有使用解决方法二。

应用场景:web应用,有请求发生并且请求被Filter拦截的情况