jinleis 2012-09-07
Hibernate与延迟加载: Hibernate对象关系映射提供延迟的与非延迟的对象初始化。非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来。这有时会导致成百的(如果不是成千的话) select 语句在读取对象的时候执行。这个问题有时出现在使用双向关系的时候,经常会导致整个数据库都在初始化的阶段被读出来了。当然,你可以不厌其烦地检查每一个对象与其他对象的关系,并把那些最昂贵的删除,但是到最后,我们可能会因此失去了本想在 ORM 工具中获得的便利。
一个明显的解决方法是使用Hibernate提供的延迟加载机制。这种初始化策略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来。这个过程对开发者来说是透明的,而且只进行了很少的数据库操作请求,因此会得到比较明显的性能提升。这项技术的一个缺陷是延迟加载技术要求一个Hibernate会话要在对象使用的时候一直开着。这会成为通过使用DAO模式将持久层抽象出来时的一个主要问题。为了将持久化机制完全地抽象出来,所有的数据库逻辑,包括打开或关闭会话,都不能在应用层出现。最常见的是,一些实现了简单接口的DAO实现类将数据库逻辑完全封装起来了。一种快速但是笨拙的解决方法是放弃DAO模式,将数据库连接逻辑加到应用层中来。这可能对一些小的应用程序有效,但是在大的系统中,这是一个严重的设计缺陷,妨碍了系统的可扩展性。
在 Web 层进行延迟加载 幸运的是, Spring 框架为 Hibernate 延迟加载与 DAO 模式的整合提供了一种方便的解决方法。对那些不熟悉 Spring 与 Hibernate 集成使用的人,我不会在这里讨论过多的细节,但是我建议你去了解 Hibernate 与 Spring 集成的数据访问。以一个 Web 应用为例, Spring 提供了 OpenSessionInViewFilter 和 OpenSessionInViewInterceptor 。我们可以随意选择一个类来实现相同的功能。两种方法唯一的不同就在于 interceptor 在 Spring 容器中运行并被配置在 web 应用的上下文中,而 Filter 在 Spring 之前运行并被配置在 web.xml 中。不管用哪个,他们都在请求将当前会话与当前(数据库)线程绑定时打开 Hibernate 会话。一旦已绑定到线程,这个打开了的 Hibernate 会话可以在 DAO 实现类中透明地使用。这个会话会为延迟加载数据库中值对象的视图保持打开状态。一旦这个逻辑视图完成了, Hibernate 会话会在 Filter 的 doFilter 方法或者 Interceptor 的 postHandle 方法中被关闭。下面是每个组件的配置示例:Interceptor的配置:
<beans> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="interceptors"> <list> <ref bean="openSessionInViewInterceptor"/> </list> </property> <property name="mappings"> ... </bean> ... <bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor"> <property name="sessionFactory"><ref bean="sessionFactory"/></property> </bean> </beans>
Filter的配置
<web-app> ... <filter> <filter-name>hibernateFilter</filter-name> <filter-class> org.springframework.orm.hibernate.support.OpenSessionInViewFilter </filter-class> </filter> ... <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>*. spring </url-pattern> </filter-mapping> ... </web-app>