Hibernate和延迟加载
Hibernate对象关系映射提供了两种对象化模式:延迟加载和非延迟加载非延迟加载在加载时获取对象本身以及它关联所有对象这可能导致在获取个例子时执行成百上千select语句当使用双向关联时这个问题被放大常常出现化请求时整个数据库都被载入显然检查每个对象关系并手工删除他们会费点事但最终我们可能会因此丢失使用ORM工具优势个明细解决方式是使用hibernate提供延迟载入机制这种化策略在类成员被访问时只载入它个对象对多和多对多关系对开发人员来说这种方式是透明并且只有最少数量请求发生这样就获得了最佳性能这种技术个缺点是延迟载入要求当对象还在使用中时HibernateSession必须保持打开状态当尝试通过DAO模式抽象持久层时这会引起个重要问题为了充分地抽象持久层所有数据库逻辑包括打开、关闭Session都不能在应用层出现最常见是这些逻辑隐藏在DAO实现类中快速和差些方案是:避免采用DAO模式在应用层中包含数据连接逻辑这在小应用中是可行但在大系统中这会是个设计缺陷它损害了应用扩展性
在Web层使用延迟加载
幸运是Spring框架已经提供了个DAO模式结合Hibernate延迟加载Web方案对于任何不熟悉Spring框架结合Hibernate人来说我在这里不会深入细节但是我希望你去阅读“结合Spring框架Hibernate数据库访问”章节这个案例是个Web应用Spring提供了OpenSessionInViewerFilter和OpenSessionInViewInterceptor使用它们中任个都能获得同样功能这两者唯区别是erceptor在Spring容器中运行并且在web应用上下文中配置;fitler在Spring前运行并且在web.xml中配置不管使用哪个他们都会在请求绑定到Session当前线程期间打开Hibernate Session旦绑定到线程打开Hibernate Session能被DAO实现类透明地使用Session会持续打开允许延加载访问数据库旦View逻辑完成hibernate session会被关闭无论是在FilterdoFilter思路方法中还是在InterceptorpostHandle思路方法中下面是个配置例子:
Interceptor配置
<beans>
<bean id="urlMapping"
="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="erceptors">
<list>
<ref bean="openSessionInViewInterceptor"/>
</list>
</property>
<property name="mappings">
...
</bean>
...
<bean name="openSessionInViewInterceptor"
="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->
org.springframework.orm.hibernate.support.OpenSessionInViewFilter
</filter->
</filter>
...
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>*.spring</url-pattern>
</filter-mapping>
...
</web-app>
使用打开sessionHibernateDAO实现类很简单实际上如果你已经使用Spring框架实现HibernateDAO对象最有可能是你不
需要做任何改动DAO必须通过方便HibernateTemplate工具访问Hibernate这对数据库访问来说就是小菜碟下面是个DAO例子
DAO例子
public HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {
public Product getProduct(Integer productId) {
(Product)getHibernateTemplate.load(Product., productId);
}
public Integer saveProduct(Product product) {
(Integer) getHibernateTemplate.save(product);
}
public void updateProduct(Product product) {
getHibernateTemplate.update(product);
}
}
在业务层使用延迟加载
甚至在表现层外Spring框架也通过AOP拦截器HibernateInterceptor提供了便利延迟加载支持hibernate拦截器透明地拦截了配置在
Spring应用上下文中业务对象在前打开hibernate session在结束时关闭这个session让我们通过个简单例子
来介绍说明假设我们有个erface叫做BussinessObject:
public erface BusinessObject {
public void doSomethingThatInvolvesDaos;
}
类BusinessObjectImpl实现了BusinessObject接口:
public BusinessObjectImpl implements BusinessObject {
public void doSomethingThatInvolvesDaos {
// lots of logic that calls
// DAO es Which access
// data objects lazily
}
}
通过Spring上下文些配置我们可以让HibernateInterceptor拦截对BusinessObjectImpl允许它思路方法延迟访问数据对象
看下下面片断:
<beans>
<bean id="hibernateInterceptor" ="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="businessObjectTarget" ="com.acompany.BusinessObjectImpl">
<property name="someDAO"><ref bean="someDAO"/></property>
</bean>
<bean id="businessObject" ="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="businessObjectTarget"/></property>
<property name="proxyInterfaces">
<value>com.acompany.BusinessObject</value>
</property>
<property name="erceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
</beans>
当businessObject例子被引用HibernateInterceptor打开个hibernate session并允许对BussinessObjectImpl当BusinessOjbectImpl执行完成HibernateInterceptor透明关闭这个session应用代码并不知道任何持久层逻辑但它仍然能够使用
延迟加载访问数据对象
在单元测试中使用延迟加载
最后我们要在JUnit中测试我们延迟加载应用覆盖TestCase类Up和tearDown思路方法非常容易我更喜欢将这段代码放在个简便
抽象TestCase类中作为我所有测试基类
public abstract MyLazyTestCase extends TestCase {
public void Up throws Exception {
super.Up;
SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
Session s = sessionFactory.openSession;
TransactionSynchronizationManager.bindResource(sessionFactory, SessionHolder(s));
}
protected Object getBean(String beanName) {
//Code to get objects from Spring application context
}
public void tearDown throws Exception {
super.tearDown;
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
Session s = holder.getSession;
s.flush;
TransactionSynchronizationManager.unbindResource(sessionFactory);
SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory);
}
最新评论