`

Spring学习笔记(七)——Spring持久化服务 DAO JDBC ORM

阅读更多
对于RDBMS相关的应用而言,应用提供的持久化服务很重要。
1.背景
借助于Spring框架提供的DAO抽象,开发者能够以统一的方式同数据访问技术(比如,JDBC、Hibernate、JDO、TopLink)进行交互。Spring DAO抽象允许开发者在不同数据访问技术间切换,且不用考虑异常处理,Spring提供了统一的异常处理机制。
在Java/J2EE领域,JDBC是访问RDBMS的标准。在O/R Mapping技术出来前,开发者需要直接借助于JDBC和SQL进行RDBMS操作。借助于O/R Mapping技术,能将对象属性映射到RDBMS表的列、将对象映射到RDBMS表,这些Mapping技术能为应用自动创建高效的SQL语句。此外,O/R Mapping技术还提供了延迟装载、(分布式)缓存等高级特征。使用O/R Mapping技术,能大量节省开发时间,减少代码量及开发成本。
在特定场合,还是需要使用JDBC实现与RDBMS的交互,Spring为JDBC提供了抽象层,让JDBC的使用更有效。
就目前的O/R Mapping技术而言,大部分局限在RDBMS表相关的操作,还不能使用到存储过程等其他操作类型。这对于以数据为中心的应用而言,使用表之外的RDBMS功能很突出,因此,提供Spring JDBC抽象是实用的、必需的。
OR Mapping能够完成对象到关系的映射;O/X(Object/XML Mapping)能完成对象到XML的映射。关系同XML的含义是一致的,关系更多的是横向看待问题;XML更多的是从纵向看待问题。无论是横向还是纵向,JavaBean表达这种关系尤为合适,因为JavaBean的属性能关联到其他的JavaBean。因此JavaBean(POJO)在持久化服务中担任重要角色,比如Hibernate。
借助于O/R Mapping技术,能解决工业领域80%的数据持久化问题。Spring为其提供了优秀的支持能力。
通过使用Spring对它们的集成支持,还能享受到集成带来的其他优势,比如,智能处理异常的能力、集成事务管理能力,通过Spring提供的线程安全模版类、资源管理能力(比如连接池、数据库连接)、实用类等。
2.Spring对DAO提供的支持
通过Spring DAO抽象,能将具体的DAO技术的异常,比如HibernateException、SQLException,转换成以DataAccessException为根的异常处理体系中。由于以DataAccessException为根的异常处理体系中的异常类只是对具体的DAO技术的异常进行包裹,即不会丢失任何异常信息,因此使用DataAccessException很安全。
当使用O/R Mapping访问框架的模版(比如,JdbcTemplate,HibernateTemplate)时,不用考虑是否需要处理异常,Spring DAO会完成这些操作。
当使用拦截器(比如,HibernateInterceptor)时,必须手工处理具体DAO技术中的异常。这对于需要处理业务相关异常的系统而言,更加灵活。借助于Sping中的SessionFactoryUtils实用类能将具体的DAO异常转化为Spring DAO抽相中定义的异常。
Spring提供了一套抽象DAO类,供扩展使用,有利于以统一的方式操作各种DAO技术,比如JDO,JDBC。这些抽象类提供了设置数据源和相关辅助信息的方法,而其中的一些方法同具体DAO技术有关。
目前Spring DAO提供的抽象有如下几种:
a)JdbcDaoSupport:JDBC DAO抽象类。需要为它配置数据源(DataSource)。通过其子类,可以获得JdbcTemplate,也可以手工配置JdbcTemplate。
b)HibernateDaoSupport:Hibernate DAO抽象类。需要为它配置HibernateSessionFactory。通过其子类,开发者可以获得HibernateTemplate,也可以手工配置HibernateTemplate。
c)JdoDaoSupport:Spring为JDO提供的DAO抽象类。需要配置PersistenceManagerFactory。通过子类,可以获得JdoTemplate,也可以手工配置JdoTemplate。

3.Spring对JDBC提供的支持

无论何种O/R Mapping技术,最终于RDBMS交互的技术一般都是JDBC。因此,在Java/J2EE领域中,JDBC是最为重要的、基础的技术。
直接采用JDBC开发,开发者能细粒度的调整访问RDBMS的性能,而且能使用到RDBMS专属的功能。对于主流的RDBMS而言,一般都存在相应的JDBC规范实现,比如用于开发者的JDBC Driver、JDBC实用类等。
然而,JDBC同RDBMS是紧耦合的,不便于在不同的RDBMS间移植。虽然JDBC的目标是实现java应用的便携,但有些场合,往往需要提供RDBMS专属的功能。比如,主流的Hibernate也需要为各种RDBMS提供不同的方言(Dialect)。
借助于Spring提供的JDBC抽象,能消除很多重复代码。
3.1)JdbcTemplate
JdbcTemplate同其他J2EE组件技术类似,比如JMS、JTA,是Spring借助于JDBC操作RDBMS而提供的实用模版类。JdbcTemplate能自动管理数据库连接资源的打开和关闭操作,简化使用。
在使用JdbcTemplate前,需要配置JdbcTemplate使用到的DataSource。由于Spring中所有的模版类都是线程安全的,对于各个DataSource而言,开发者只需要在Spring配置文件中配置单个的JbdcTemplate,即可满足多线程使用。
  
<bean id="jdbcTemplate"
                   class="org.springframework.jdbc.core.JdbcTemplate">
                   <property name="dataSource">
                           <ref local="dataSource"></ref>
                   </property>
   </bean>

   <bean id="dataSource" 
                class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName">
                <value>org.gjt.mm.mysql.Driver</value>
        </property>
        <property name="url">
                <value>jdbc:mysql://localhost:3306/example11</value>
        </property>
        <property name="username">
                <value>root</value>
        </property>
        <property name="password">
                <value></value>
        </property>
    </bean>


可以再应用的代码中直接使用JdbcTemplate,通过JdbcTemplate,可以执行SQL语句。只要提供了DataSource和JdbcTemplate。
JdbcTemplate支持的JDBC操作很多。同Spring其他模版类似,Spring DAO JDBC抽象提供了同JdbcTemplate配套使用的若干回调接口,比如:PreparedStatementCreator、CallableStatementCreator、RowCallbackHandler接口。

3.2)DataSourceTransactionManager
对于单一的JDBC数据源而言,开发者可以使用PlatformTransactionManager接口的如下实现,即DataSourceTransactionManager。为使用DataSourceTransactionManager实现事务管理,必须使用DataSourceUtils.getConncetion(DataSource)方法,以获得JDBC连接,而不能使用标准的J2EE DataSource.getConnection。主要原因有二:其一,DataSourceUtils.getConncetion(DataSource)能抛出Sping DAO抽象框架内的未受查异常,便于DAO抽象框架进行异常处理。其二,界定事务边界,即确保返回的数据库连接绑定到当前线程,从而实现事务管理功能。
DataSourceTransactionManager支持设置事务超时时间,即通过DataSourceUtils的applyTransactionTimeout方法,对于不需要支持分布式事务管理的场合,即使用JTA,只需使用DataSourceTransactionManager就可以。

3.3)连接数据库的方式
JdbcTemplate在操作数据库时,需要为它提供数据源。一般情况下,存在以下几种RDBMS数据源:
a)SingleConnectionDataSource:实现了SmartDataSource接口。不具备多线程能力,主要供开发时使用
b)DriverManagerDataSource:实现了SmartDataSource接口。每次客户请求,都会返回新的JDBC连接。
另外,基于目标环境的不同,可以使用不同的数据源类型,比如DBCP BasicDataSource。当然,在实际应用环境中,基于JNDI获取数据源的比较常见。

3.4)将JDBC操作建模为java对象
其中,org.springframework.jdbc.object包中提供的类允许发开着以OO的方式访问数据库。借助于object包,能将查询结果中的数据库列映射到业务对象的属性上。同时,还能执行存储过程,及CRUD操作。
其次,还需要实现MappingSqlQuery接口类,直接使用实现类并可操作到RDBMS。

4.Spring对ORM提供的支持
Spring框架依据资源管理、DAO实现支持、事务策略,对Hibernate、JDO、iBATIS SQL Maps进行了集成。
Spring框架对Hibernate进行了最深入的集成,借助于Spring Ioc和Spring AOP对Hibernate的集成问题进行了最有效的集成。
4.1)Hibernate
Hibernate不仅提供了O/R Mapping功能,还支持很多高级特性。Hibernate3.0中新增大量的特性,包括对存储过程和手工编写sql的支持。通过xml配置文件能够将对象映射到RDBMS。
一般而言,开发Hibernate应用需要准备如下内容:
a)Hibernate配置文件。一般可通过两种方式进行。其一,提供hibernate.cfg.xml文件,用于创建Hibernate SessionFactory。其二,提供hibernate.properties文件。推荐使用xml文件。
b)Hibernate映射文件。比如Interest.hbm.xml。
c)POJO类源文件。比如com.openv.spring.Interest.java。
现在有一些免费的支持工具,比如Hibernate Middlegen、Hibernate Synchronizer、Hibernate Tools。
Hibernate Synchronizer是免费的,能同Hibernate持久框架配合生产代码的工具。它是以Eclipse插件方式运行的。当开发者修改了Hibernate映射文件后,Hibernate Synchronizer会自动修改POJO代码。
其中,生成的代码包括两部分。其一,以抽象基类存在的源代码。其二,开发者能够修改的扩展类。由于Hibernate Synchronizer并不会自动同步扩展类,因此不会因为RDBMS表结构的修改,而修改了扩展类,这对于在扩展类中开发业务相关逻辑,或者重载抽象类中的方法很有利。借助于Hibernate Synchronizer,能够自动创建如下类型的对象:
●值对象
●代理接口
●复合键对象
●枚举对象
●组建对象
●子类
●DAO

4.2)Hibernate集成支持
基于Hibernate开发java应用的过程很简单,即可完成同RDBMS的交互。但是,直接借助于Hibernate API开发应用也存在一些问题:
●尽管借助于Hibernate Synchronizer工具能生产DAO代码,但如果RDBMS表数量很多,维护这些DAO代码很费时间
●如果应用系统需要将ORMapping技术替换掉,则在开发应用系统时,开发者还需要引入另外一层,以处理这种“适配器”层。这不利于代码的维护,也很难复用。
●如果需要在Web/J2EE应用中使用Hibernate,则还需要开发集成层。
基于上面问题,Spring引入了Hibernate集成。
1)定义Hibernate资源
对于Web/J2EE应用而言,开发者可以通过在Spring配置文件中定义sessionFactory时,给出Hibernate映射文件的定义。示例如下:
   
//通过JNDI获得对RDBMS数据源的引用
    <bean id="dataSource" 
                class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName">
            <value>java:/MySqlDS</value>
        </property>
    </bean>

        //基于LocalSessionFactoryBean定义sessionFactory
        <bean id="sessionFactory" 
                class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
                //引用上述定义的RDBMS数据源,即dataSource
                <property name="dataSource">
                        <ref local="dataSource"/>
                </property>
                
                //定义Hibernate映射文件(资源)
                <property name="mappingResources">
                        <list>
                                <value>
                                        com/openv/spring/service/hibernate/Interest.hbm.xml
                                </value>
                                <value>
                                        com/openv/spring/service/hibernate/UserInterest.hbm.xml
                                </value>
                                <value>
                                        com/openv/spring/service/hibernate/UserInfo.hbm.xml
                                </value>
                        </list>
                </property>
                //定义Hibernate配置属性
                <property name="hibernateProperties">
                        <props>
                                <prop key="hibernate.dialect">
                                        net.sf.hibernate.dialect.MySQLDialect
                                </prop>
                                <prop key="hibernate.show_sql">
                                        true
                                </prop>
                        </props>
                </property>
        </bean>


因此,使用Spring DAO抽象提供的Hibernate集成使得应用代码不用硬编码对资源进行查找,比如对JDBC DataSource、Hibernate SessionFactory的查找和获得。对于那些需要访问资源的应用对象而言,借助于JavaBean引用便能实现对资源的使用,如上例中对dataSource的引用。
如果开发者需要动态更换datasource,则只需要修改Spring配置文件。
另外,由于JBoss 3.2.x和JBoss 4.0.x都集成对Hibernate的支持,借助于JNDI能够实现对SessionFactory的引用。因此,从Spring中对Hibernate资源的使用方式,就可以看出其实用性。
2)HibernateTemplate、HibernateDaoSupport
同JTA、JMS、JDBC一样,Spring DAO Hibernate抽象也提供了HibernateTemplate。HibernateTemplate充分利用了Spring IoC特性,从而实现对Hibernate资源的依赖注入。
如果应用只是用Spring Ioc,则只需要在Spring配置文件中为其提供sessionFactory。Spring框架还提供了另一个实用类,即HibernateDaoSupport。通过继承HibernateDaoSupport,可以在继承类中借助于getHibernateTmplate()以获得对Hibernate资源的操作。
当然,如果打算直接使用HibernateTemplate,则需要做如下几方面的工作。
a)需要在userinfoDAO定义中引用sessionFactory。
      
 <bean id="userinfoDAO" 
                class="com.openv.spring.service.dao.impl.UserInfoDAO">
                <property name="sessionFactory">
                        <ref local="sessionFactory"/>
                </property>
        </bean>

b)需要在UserInfoDAO中定义sessionFactory变量,并提供setter方法,即setSessionFactory方法,供Spring IoC容器实现对sessionFactory的依赖注入。
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
        this.sessionFactory = sessionFactory;
}

c)在实现对Hibernate的调用过程中,需要实现HibernateCallback回调接口。
public List getInterests() throws DataAccessException{
        List list = new AarrayList();
        HibernateTemplate hibernateTemplate = 
          new HibernateTemplate(this.sessionFactory);
        List interestList = 
          (List)hibernateTemplate.execute(
           new HibernateCallback() {
              public Object doInHibernate(Session session) throws HibernateException {
                 List result = session.find("select interest.name from Interest interest");
                 return result;
              }
           }
        );
        ......
        return list;
}

由此可见,这种回调实现能实现基于Hibernate的DAO访问。而且,HibernateTemplate能保证正确的打开和关闭Hibernate Session,并自动参与到事物中。同其他模板一样,HibernateTemplate也是线程安全的(通过可重入实现),并且可以重用。对于简单的Hibernate操作,比如单个find、saveOrUpdate操作,直接使用HibernateTemplate
3)HibernateInteceptor
Spring框架也为开发者提供了使用Hibernate的另一种方式,既不需使用HibernateTemplate,而使用HibernateInterception拦截器。具体操作方式是,直接将Hibernate API代码嵌入在try/catch块中,并且在Spring配置文件中配置好拦截器。
同使用HibernateTemplate相比,使用HibernateInterceptor允许开发者捕捉任何受查异常,而基于HibernateTemplate的应用代码却不能够,因为它只能捕捉回调接口中的未受查异常。但是,在使用便利方面,HibernateTemplate更方便。
4)Hibernate事务管理
借助于TransactionProxyFactoryBean能够实现声明式事务的使用,对于Hibernate而言也适用。
TransactionProxyFactoryBean是Spring框架提供的便利类。使用它的前提是在Spring配置中没有涉及到其他Spring AOP拦截器。它实现了TransactionInterceptor的功能。而且在配置上没有TransactionInterceptor复杂。因此推荐,在一些场合(比如,业务比较复杂时),直接使用TransactionProxyFactoryBean,以实现声明式事务,这对于Hiberante和非Hibernate应用都适用。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics