`
sumongh
  • 浏览: 226530 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

论Spring与Hibernate的延迟加载和Dao模式

阅读更多
Spring Hibernate 的延迟加载和 Dao 模式

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>

实现 Hibernate Dao 接口来使用打开的会话是很容易的。事实上,如果你已经使用了 Spring 框架来实现你的 Hibernate Dao, 很可能你不需要改变任何东西。方便的 HibernateTemplate 公用组件使访问数据库变成小菜一碟,而 DAO 接口只有通过这个组件才可以访问到数据库。下面是一个示例的 DAO


Example DAO

public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO {

public Product getProduct(Integer productId) {
return (Product)getHibernateTemplate().load(Product.class, productId);
}

public Integer saveProduct(Product product) {
return (Integer) getHibernateTemplate().save(product);
}

public void updateProduct(Product product) {
getHibernateTemplate().update(product);
}
}

在业务逻辑层中使用延迟加载

即使在视图外面, Spring 框架也通过使用 AOP interceptor HibernateInterceptor 来使得延迟加载变得很容易实现。这个 Hibernate interceptor 透明地将调用配置在 Spring 应用程序上下文中的业务对象中方法的请求拦截下来,在调用方法之前打开一个 Hibernate 会话,然后在方法执行完之后将会话关闭。让我们来看一个简单的例子,假设我们有一个接口 BussinessObject


public interface BusinessObject {
public void doSomethingThatInvolvesDaos();
}
The class BusinessObjectImpl implements BusinessObject:


public class BusinessObjectImpl implements BusinessObject {
public void doSomethingThatInvolvesDaos() {
// lots of logic that calls
// DAO classes Which access
// data objects lazily
}
}
通过在 Spring 应用程序上下文中的一些配置,我们可以让将调用 BusinessObject 的方法拦截下来,再令它的方法支持延迟加载。看看下面的一个程序片段:


<beans>
<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl">
<property name="someDAO"><ref bean="someDAO"/></property>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="businessObjectTarget"/></property>
<property name="proxyInterfaces">
<value>com.acompany.BusinessObject</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
</beans>
businessObject 被调用的时候, HibernateInterceptor 打开一个 Hibernate 会话,并将调用请求传递给 BusinessObjectImpl 对象。当 BusinessObjectImpl 执行完成后, HibernateInterceptor 透明地关闭了会话。应用层的代码不用了解任何持久层逻辑,还是实现了延迟加载。


在单元测试中测试延迟加载

最后,我们需要用 J-Unit 来测试我们的延迟加载程序。我们可以轻易地通过重写 TestCase 类中的 setUp tearDown 方法来实现这个要求。我比较喜欢用这个方便的抽象类类作为所有我的测试类的基类。


public abstract class MyLazyTestCase extends TestCase {

private SessionFactory sessionFactory;
private Session session;

public void setUp() throws Exception {
super.setUp();
SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory");
session = SessionFactoryUtils.getSession(sessionFactory, true);
Session s = sessionFactory.openSession();
TransactionSynchronizationManager.bindResource(sessionFactory, new 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);
}
}

 

由于要求在项目中使用泛型的DAO,所以上网Google了一下,找到了IBM的一篇文章。文章讲得不错,但是有些地方不清楚,如果完全按照那篇文章可能还会遇到一些困难。所以写了这篇文章,解释如何在项目中加入泛型的DAO实现。

首先是总的类关系的UML图:

然后是在配置文件中的关系图:  

其中,IStaffDao是我们自己定义的接口,这个接口类似:

public   interface  IStaffDAO  extends  GenericDao < Staff, Integer >

public  List listAll(); 

public  Staff getByLogonAndId(String logon, Integer id); 

// more  

}
 

 

GenericDao<T , PK extends Serilizable> 是泛型的 Dao 接口:

/** */ /**
 * 2006-11-22
 * 范型DAO接口
 * 
@author  Zou Ang
 * Contact <a href ="mailto:richardeee@gmail.com">Zou Ang</a>
 
*/

public   interface  GenericDao < T, PK  extends  Serializable >   {

    
/** */ /**
     * 保存一个对象到数据库
     * 
@param  newInstance 需要保存的对象
     * 
@return
     
*/

    PK create(T newInstance);
    
/** */ /**
     * 从数据库读取一个对象
     * 
@param  id 主键
     * 
@return
     
*/

    T read(PK id);
    
    
/** */ /**
     * 更新一个对象
     * 
@param  transientObject 被更新的对象
     
*/

    
void  update(T transientObject);
    
    
/** */ /**
     * 删除一个对象
     * 
@param  transientObject 被删除的对象
     
*/

    
void  delete(T transientObject);
}

 

GenericDaoHibernateImpl GenericDao 接口的泛型实现 :

 


/** */ /**
 * 2006-11-22
 * 范型DAO实现
 * 
@author  Zou Ang
 * Contact <a href ="mailto:richardeee@gmail.com">Zou Ang</a>
 
*/

public   class  GenericDaoHibernateImpl < T,PK  extends  Serializable >  
    
extends  HibernateDaoSupport 
        
implements  GenericDao < T, PK >  ,FinderExecutor {
    
    
private  Class < T >  type;
    
private  FinderNamingStrategy namingStrategy  =   new  SimpleFinderNamingStrategy();  //  Default. Can override in config
     private  FinderArgumentTypeFactory argumentTypeFactory  =   new  SimpleFinderArgumentTypeFactory();  //  Default. Can override in config
    
    
public  GenericDaoHibernateImpl(Class < T >  type) {
        
this .type  =  type;
    }


    
/**/ /*  (non-Javadoc)
     * @see com.gdnfha.atcs.common.service.dao.GenericDao#create(java.lang.Object)
     
*/

    
public  PK create(T newInstance)  {
        
return  (PK)getHibernateTemplate().save(newInstance);
    }


    
/**/ /*  (non-Javadoc)
     * @see com.gdnfha.atcs.common.service.dao.GenericDao#delete(java.lang.Object)
     
*/

    
public   void  delete(T transientObject)  {
        getHibernateTemplate().delete(transientObject);
    }


    
/**/ /*  (non-Javadoc)
     * @see com.gdnfha.atcs.common.service.dao.GenericDao#read(java.io.Serializable)
     
*/

    
public  T read(PK id)  {
        
return  (T)getHibernateTemplate().get(type, id);
    }


    
/**/ /*  (non-Javadoc)
     * @see com.gdnfha.atcs.common.service.dao.GenericDao#update(java.lang.Object)
     
*/

    
public   void  update(T transientObject)  {
        getHibernateTemplate().update(transientObject);
    }


    
public  List < T >  executeFinder(Method method,  final  Object[] queryArgs)
    
{
        
final  Query namedQuery  =  prepareQuery(method, queryArgs);
        
return  (List < T > ) namedQuery.list();
    }


    
public  Iterator < T >  iterateFinder(Method method,  final  Object[] queryArgs)
    
{
        
final  Query namedQuery  =  prepareQuery(method, queryArgs);
        
return  (Iterator < T > ) namedQuery.iterate();
    }

    
    
private  Query prepareQuery(Method method, Object[] queryArgs)
    
{
        
final  String queryName  =  getNamingStrategy().queryNameFromMethod(type, method);
        
final  Query namedQuery  =  getSession().getNamedQuery(queryName);
        String[] namedParameters 
=  namedQuery.getNamedParameters();
        
if (namedParameters.length == 0 )
        
{
            setPositionalParams(queryArgs, namedQuery);
分享到:
评论

相关推荐

    Hibernate延迟加载以及利用Spring

    ### Hibernate延迟加载以及利用Spring #### 一、Hibernate延迟加载概念与原理 在理解Hibernate的延迟加载机制之前,我们首先需要了解什么是延迟加载。延迟加载(Lazy Loading)是一种设计模式,其核心思想是在真正...

    Spring 和Hibernate 整合笔记和jar包

    - **懒加载(Lazy Loading)**:Hibernate支持关联对象的延迟加载,避免一次性加载大量数据。 - **批处理**:Spring可以设置批处理大小,批量处理数据库操作,提升效率。 7. **测试与调试** - **单元测试**:...

    Struts,Spring与hibernate集成

    10. **处理Hibernate延迟加载问题**:为了解决由于Session生命周期和HTTP请求生命周期不匹配导致的延迟加载问题,可以使用OpenSessionInViewFilter。这个过滤器确保Session在请求结束时才关闭,从而能正确处理延迟...

    ssh集成jar包,支持spring集成Hibernate,spring集成struts2等

    - Hibernate支持延迟加载(Lazy Loading),提高性能,只在需要时加载数据。 - 使用SessionFactory和Session接口进行数据库会话管理,支持HQL(Hibernate Query Language)和SQL进行查询。 3. **Struts2框架**: ...

    Struts,Spring,Hibernate三大框架的面试&笔试题

    3. Hibernate的延迟加载:实体对象和集合的延迟加载策略,以及在何时真正加载数据以提高性能。 4. Struts1的流程:MVC模式下的请求处理步骤,包括ActionServlet、ActionForm、Action和视图的交互。 5. Struts与...

    SSH(struts+spring+hibernate)面试题总结

    SSH,即Struts、Spring和Hibernate,是Java开发中常用的一种技术栈,主要用于构建企业级应用。这三种框架分别在MVC模式中的表现层、业务层和服务层起到关键作用。以下是对SSH面试题中涉及的一些核心知识点的详细解释...

    Spring2.5+Hibernate3.2开发手册

    3. **实体生命周期管理**:支持了预加载(pre-fetching)和延迟加载(lazy-loading),以及更灵活的实体状态管理,比如“脱管”(detached)状态。 4. **更丰富的类型支持**:包括对数组、集合和自定义类型的支持,...

    Spring整合Hibernate示例完整代码

    10. **性能优化**:整合Spring和Hibernate后,我们可以通过配置和最佳实践优化性能,如批量操作、延迟加载、缓存策略等。 总的来说,Spring整合Hibernate能带来更优雅的代码结构、强大的事务管理和灵活的数据库操作...

    hibernate和spring技术难点及其要点总结

    1. **HibernateDaoSupport与JdbcDaoSupport**:Spring提供了这些支持类来简化DAO(数据访问对象)的实现,两者分别用于Hibernate和JDBC操作。它们提供了事务管理和数据源的便捷接入。 **三、Hibernate的查询方式** ...

    spring-orm-hibernate4源码

    7. **懒加载和级联操作**: Hibernate支持对象关系的懒加载,通过`lazy="true"`可以延迟加载关联数据。级联操作允许在一次主对象的操作中处理相关联的对象,如`CascadeType.ALL`表示对关联对象的所有操作都进行级联。...

    Tapestry5 + spring + hibernate 开发指南

    Hibernate 延迟加载配置 - **实体属性**:标记为懒加载以提高性能。 - **集合属性**:对于多对多或一对多关系使用懒加载。 #### IX. 结论 本文档提供了一个关于如何使用 Tapestry5、Spring 和 Hibernate 构建 ...

    struts+spring+Hibernate

    2. **Hibernate 3 及以上版本**:除了实体和集合的延迟加载外,还支持属性级别的延迟加载。即只有在程序真正需要某个属性时才会加载该属性。 **优点**:延迟加载可以显著减少服务器内存占用,提高服务器性能。 ###...

    hibernate和spring笔记

    **hibernate与spring整合详解** 在Java Web开发中,Hibernate和Spring是两个非常重要的开源框架,它们分别在对象关系映射(ORM)和依赖注入(DI)领域扮演着核心角色。Spring框架提供了全面的企业级应用开发解决...

    spring+hibernate

    Spring 和 Hibernate 是两个非常重要的 Java 开发框架,它们在企业级应用开发中有着广泛的应用。Spring 是一个全面的后端开发框架,而 Hibernate 则是一个流行的对象关系映射(ORM)工具,主要用于处理数据库交互。...

    集成 Flex, Spring, Hibernate 构建应用程序.docx

    Hibernate支持延迟加载、分布式缓存等功能,提高了开发效率和性能。在分层的J2EE架构中,Hibernate常被用作数据持久化层,负责业务逻辑层与数据库之间的交互。 文章以一个在线宠物商店的示例程序来展示集成Flex、...

    spring-hibernate

    5. **延迟加载(Lazy Loading)**:Hibernate 支持懒加载,只有在真正需要时才加载关联的对象,减少数据库交互,提高性能。 结合使用 Spring 和 Hibernate: 1. **整合配置**:Spring 可以管理 Hibernate 的 ...

    Flex、Spring、Hibernate 集成

    - 此外,**Spring** 还提供了事务管理、DAO支持、与各种O/R Mapping框架的集成等功能,以及对J2EE组件技术的支持,例如JavaMail、EJB、JMS和WebService等。 ### 3. Hibernate 框架 - **Hibernate** 是一个成熟的全...

    Spring MVC + hibernate 集合

    6. **懒加载和即时加载**: Hibernate 支持懒加载(延迟加载)和即时加载策略,优化性能。 三、Spring MVC 和 Hibernate 集成 1. **配置 Spring 和 Hibernate**: 在 Spring 配置文件中引入 Hibernate 相关配置,如...

    集成 Flex, Spring, Hibernate 构建应用程序.pdf

    Hibernate 支持延迟加载、缓存机制等多种高级特性,有助于提高应用性能。 #### 集成方案概述 本篇文章旨在介绍如何将 Flex、Spring 和 Hibernate 这三个技术整合起来,构建一个高效稳定的RIA应用系统。以下是对...

Global site tag (gtag.js) - Google Analytics