当持久层利用session的load()的方法去查询数据时,返回的只是虚拟代理,此时并没有真正的发送sql语句,如果在视图上使用到查询的数据时,此时sql语句才会真正发出,但这时候会话已经被关闭,无法在获取到数据。又或者在一对多的关联场景下,存在懒加载情况,也会出现延迟加载和会话关闭的矛盾。
一、利用Spring的OpenSessionInViewFilter过滤器延长会话的生命周期
web.xml中配置过滤器
<filter>
<filter-name>osiv</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>osiv</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
配置完过滤器后,session的生命周期就会延长直到视图渲染完成后才结束session。
存在的问题:
在高并发的情况下、影响性能。因为这样一来,每个从这个过滤器过的请求的session都要被延长生命周期,因为会话上绑定了数据库连接。所以很有可能使数据库连接被某些无用的session占用,导致真正需要连接的会话被阻塞。
二、利用Hibernate工具类的isInitialized方法来解决
以user为例,在控制代码中,提前初始化视图上需要用到的数据:
/*
* 利用Hibernate工具类的isInitialized方法,判断user是否被初始化
* 是的时候返回true,否则返回false
* 如果没有被初始化则用Hibernate工具类的initialize将对象初始化
*/
if(!Hibernate.isInitialized(user)) {
Hibernate.initialize(user);
}
但是这样的做法就需要我们去对代码的逻辑做一些修改,并且使方法和hibernate有了一定的耦合。
三、自定义过滤器
和Spring的OpenSessionInViewFilter一样,我们可以自己定义一个过滤器,来延长会话的生命周期。
拿到SpringIoC容器:
ServletContext sc = requset.getServletContext();
WebApplicationContext ctx =
WebApplicationContextUtils.getWebApplicationContext(sc);
从容器中取出Session并在chain.doFilter(request, response);前后分别开启和关闭会话。这种做法和Spring的OpenSessionInViewFilter没什么本质区别。