Spring的数据库支持

第一章    Spring的数据库支持
5.1 SpringDAO的支持
Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不一样的数据访问技术, JDBCHibernate或者JDO等。它不只可让你方便地在这些持久化技术间切换, 并且让你在编码的时候不用考虑处理各类技术中特定的异常。
1)  一致的异常层次
Spring提供了一种方便的方法,把特定于某种技术的异常,如SQLException, 转化为本身的异常,这种异常属于以DataAccessException 为根的异常层次。这些异常封装了原始异常对象,这样就不会有丢失任何错误信息的风险。
除了对JDBC异常的封装,Spring也对Hibernate异常进行了封装,把它们从一种专有的checked异常 (Hibernate3.0之前的版本),转化为一系列抽象的运行时异常。对JDO也是这样。 它可让你轻松处理大多数持久化异常(这些异常大可能是不可恢复的,并且只出如今特定 的层次),而再也不须要讨厌的样板式catch/throw代码块和异常声明。你仍然能够在须要 的地方捕获并处理这些异常。就像咱们上面提到的,JDBC异常(包括特定于某种数据库 方言的异常)也能够被转化为一样的异常层次,这意味着你能够在一致的编程模型下,通 过JDBC来执行某些操做。
上述状况适用于各类使用模板方式的ORM访问框架。若是使用拦截器方式,你在应用中 就得本身当心处理HibernateException JDOException等,最好是委托给 SessionFactoryUtils convertHibernateAccessException convertJdoAccessException等方法。这些方法能够把相应的异常转 化为与org.springframework.dao中定义的异常层次相兼容的异常。其中JDOExceptionunchecked异常,它们则被简单地抛出,尽管这在异常处理方面牺牲了通用的DAO抽象。
2) 一致的DAO支持抽象类
为了便于以一种一致的方式使用各类数据访问技术,如JDBCJDOHibernate Spring提供了一套抽象DAO类供你扩展。这些抽象类提供了一些方法,经过它们你能够 得到与你当前使用的数据访问技术相关的数据源和其余配置信息。
Dao支持类:
JdbcDaoSupport - JDBC数据访问对象的基类。 须要一个DataSource,同时为子类提供 JdbcTemplate
HibernateDaoSupport - Hibernate数据访问对象的基类。 须要一个SessionFactory,同时为子类提供 HibernateTemplate。也能够选择直接经过 提供一个HibernateTemplate来初始化, 这样就能够重用后者的设置,例如SessionFactory flush模式,异常翻译器(exception translator)等等。
5.2 Spring中使用JDBC
Java开发人员都有过直接使用JDBC编写数据库程序的经历,因为JDBC API过于底层,开发人员不但须要编写数据操做代码,还须要编写获取JDBC连接、处理异常、释放资源等代码。即便是一个再简单不孤傲的数据库操做,也须要至少几十行的代码。Spring JDBC经过模板和回调机制大大下降了使用JDBC的复杂度,借由JdbcTemplate的帮助,咱们仅须要编写那些“必不可少”的代码就能够进行数据库操做了。
1)简单的 JdbcTemplate
代码清单1
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class JdbcDAO {
    public static void main(String[] args) {
       DriverManagerDataSource ds = new DriverManagerDataSource();
       ds.setDriverClassName( "net.sourceforge.jtds.jdbc.Driver" );
       ds.setUrl( "jdbc:jtds:Sqlserver://10.0.160.188:1433/WPE" );
       ds.setUsername( "sa" );
       ds.setPassword( "sa" );
       JdbcTemplate jdbcTemplate = new JdbcTemplate();
       jdbcTemplate.setDataSource(ds);
       String sql = "create table T_USER(U_ID int primary key ,U_NAME varchar(20))" ;
       jdbcTemplate.execute(sql);
    }
}
代码清单 1 中咱们建立了一个 DriverManagerDataSource 数据源对象,又建立了一个 JdbcTemplate 对象经过调用 JdbcTemplate 对象的 execute 方法向数据库中建立一个表。很简单的一个例子可是咱们已经感觉到 JdbcTemplate 的力量。
    2) 使用 JdbcDaoSupport
       咱们看到代码清单中的 JdbcTemplate 访问数据库是那么的简单,可是 Spring 还进一步简化了模板类的支持类, JdbcDaoSupport 自己包含了一个 JdbcTemplate 类实例变量,并开放了设置 dataSource 的接口,这样咱们仅须要简单地扩展 JdbcDaoSupport 就能够定以本身的 DAO 类了。
代码清单 2
<!-- 定义 dataSource -->
< bean id = "dataSource" class = "net.sourceforge.jtds.jdbc.Driver" >
    < property name = "driverClassName"
              value = "net.sourceforge.jtds.jdbc.Driver" />
    < property name = "url"
value = "jdbc:jtds:Sqlserver://10.0.160.188:1433/WPE" />
    < property name = "username" value = "sa" />
    < property name = "password" value = "sa" />
</ bean >
<!-- 定义 jdbcTemplate -->
< bean id = "jdbcTemplate"
           class = "org.springframework.jdbc.core.JdbcTemplate" >
    < property name = "dateSource" ref = "dataSource" />
</ bean >
<!-- 定义 dao 抽象父类用于其它类使用 -->
< bean id = "dao" abstract = "true" >
    < property name = "jdbcTemplate" ref = "jdbcTemplate" />
</ bean >
< bean id = "jdbcDAO" class = "com.tony.test.JdbcDAO" parent = "dao" />
 
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class JdbcDAO extends JdbcDaoSupport{
    public void save(String name) { // 向数据库中插入一条记录
       String sql = "INSERT INTO T_USER(U_NAME) VALUES(?)" ;
       this .getJdbcTemplate() .update(sql, new Object[]{name});
    }
}
代码清单 2 中咱们经过 Spring 的配置文件将 JdbcDAO 装配完成 , 咱们就能够经过 this .getJdbcTemplate() 得到 JdbcTemplate 对象直接操做数据库。除了标准的 JdbcTemplate 之外,在 Spring2.0 中新增了 NamedParameterJdbcDaoSupport 以提供明明参数绑定的功能。
3)NamedParameterJdbcDaoSupport
在低版本的 Spring , 用户只能使用 ? 占位符声明参数,并使用索引号绑定参数,使用这种方法绑定参数时,必须足够当心,以保证参数的索引号和 SQL 语句中占位符(?)的位置正确匹配。这种编程模式被认为是弱稳定的,由于当新增一个?占位符时,可能致使原来全部的参数绑定方法都须要所以调整索引号,这极有可能引入一些不容易发现的错误。 Spring2.0 提供了新的支持命名参数绑定的 NamedParameterJdbcDaoSupport 模板类,来一块儿看看下面的代码
代码清单 3
import org.springframework.jdbc.core.namedparam.
NamedParameterJdbcDaoSupport;
public class JdbcDAO extends NamedParameterJdbcDaoSupport{
    public void save(String name) {
       Map<String,String> value = new HashMap<String,String>();
       value.put( "U_NAME" , name); // 定义了一个 Map, name put Map
       String sql = "INSERT INTO T_USER(U_NAME) VALUES(:U_NAME)" ;
       // 调用 this .getNamedParameterJdbcTemplate() 对数据库操做
this .getNamedParameterJdbcTemplate().update(sql,value);
    }
}
    在代码清单中咱们看到使用 NamedParameterJdbcTemplate 的方法更加灵活,而且 SQL 语句也更加清晰。
5.3 SpringORM框架支持
Spring在资源管理,DAO实现支持以及事务策略等方面提供了与 HibernateJDOOracle TopLinkiBATIS SQL Mappings 以及 JPA 的集成。以Hibernate为例,Spring经过使用许多IoC的便捷特性对它提供了一流的支持,帮助咱们处理不少典型的Hibernate整合的问题。全部的这些支持,都遵循Spring通用的事务和DAO异常体系。一般来讲有两种不一样的整合风格:咱们可使用Spring提供的DAO模板,或者直接使用Hibernate/JDO/TopLink等工具的原生API编写DAO。不管采起哪一种风格,这些DAO均可以经过IoC进行配置,并参与到Spring的资源和事务管理中去。
使用Spring构建O/R Mapping DAO的好处包括:
1)      测试简单。 SpringIoC使得替换不一样的实现和配置变得很是简单,这些内容包括:Hibernate SessionFactory 的位置,JDBC DataSource,事务管理器以及映射对象的实现(若是须要)等。这样也就很容易隔离并测试持久化相关的代码的各个部分。
2)      异常封装。 Spring可以封装你所选择的O/R Mapping工具所抛出的异常,将它们从专有的、潜在的checked exception转化为一组抽象的runtime DataAccessException体系。这可使你仅须要在恰当的应用程序层次去处理大部分不可恢复的持久层异常,从而避免了不少使人讨厌的catch/throw以及异常声明。固然,你仍是能够在你须要的地方捕捉和处理异常。回想一下JDBC异常(包括与DB相关的Dialect)被转变为一样的异常体系,这就意味着你能够在一致的编程模型中处理JDBC操做。
3)      通用的资源管理。 Springapplication context可以处理诸如Hibernate SessionFactory JDBC DataSourceiBatisSQL Maps配置对象以及其余相关资源的定位和配置。这样,这些配置的值很容易被管理和修改。Spring提供了简单、有效、安全的对持久层资源的处理。以Hibernate为例,一般在使用Hibernate时,须要使用同一个Hibernate Session 对象以确保高效和恰当地事务处理。 Spring让咱们可以很容易透明地建立并绑定一个 Session 到当前线程。你可使用如下两种办法之一:经过使用一个外部的template包装类在Java代码层次实现,或者经过Hibernate SessionFactory 暴露当前 Session 对象(对于那些创建在Hibernate3原生的API上的DAO)。这样,对于任何的事务环境(本地事务或者JTA),Spring解决了许多在Hibernate使用中不断出现的这样那样的问题。
4)     综合的事务管理。 Spring容许你封装你的O/R Mapping代码,这能够经过声明式的AOP方法拦截器或者在Java代码级别上使用一个外部的template包装类。不管使用哪种方式,事务控制都会帮助你作相关处理,例如万一有异常发生时的事务操做(rollback)。正如咱们下面要讨论的同样,你可以使用和替换各类事务管理器,却不会使你的Hibernate/JDO相关的代码受到影响。例如,无论采用本地事务仍是JTA,完整的Service层的代码(如声明式事务管理)在这种场景下都是相同的。做为一个附加的功能,JDBC相关的代码可以在事务级别上与你所使用的O/R映射代码无缝整合。这一功能对于那些诸如批量处理、BLOB的操做等并不适合采用O/R Mapping操做的,可是须要与O/R Mapping操做一块儿参与相同的事务来讲是至关有用的。
5)      避免绑定特定技术容许mix-and-match的实现策略。 虽然Hibernate很是强大、灵活、开源并且免费,但它仍是使用了本身的特定的API。此外,有人也许会争辩:iBatis更轻便并且在不须要复杂的O/R映射策略的应用中使用时可以表现得很是优秀。若是能够选择的话,使用标准或抽象的API来实现主要的应用需求一般是更好的,尤为是当你可能会由于功能、性能或其余方面的缘由而须要切换到另外一种实现的时候。举例来讲,SpringHibernate事务和异常抽象,容许你经过IoC机制轻松封装mapperDAO对象来实现数据访问功能,这些特性都可以使你在 不牺牲Hibernate强大功能 的状况下在你的应用程序中隔离Hibernate的相关代码。处理DAO的高层次的service代码无需知道DAO的具体实现。这一机制能够很容易使用mix-and-match方案互不干扰地实现数据访问层(好比在一些地方用Hibernate,一些地方使用JDBC,其余地方使用iBatis), mix-and-match的特性也有利于处理遗留代码并在各类技术(JDBCHibernateiBatis)之间取长补短。
咱们将首先从Hibernate开始,经过讲解HibernateSpring环境中的使用来阐述Spring框架对于O/R Mapping工具的整合方式。本章节将涉及到许多细节问题,并向你展现各类不一样的DAO实现方式和事务划分。这其中的绝大多数模式可以被Spring支持的其余O/R Mapping工具所使用。为了不硬编码的资源查找与应用程序对象紧密耦合,Spring容许你在application context中以bean的方式定义诸如JDBC DataSource或者Hibernate SessionFactory 的数据访问资源。任何须要进行资源访问的应用程序对象只须要持有这些事先定义好的实例的引用,下面的代码演示如何建立一个Hibernate SessionFactory
代码清单1
<!-- 定义 dataSource -->
< bean id = "dataSource" class = "net.sourceforge.jtds.jdbc.Driver" >
    < property name = "driverClassName"
           value = "net.sourceforge.jtds.jdbc.Driver" />
    < property name = "url"
value = "jdbc:jtds:Sqlserver://10.0.160.188:1433/WPE" />
    < property name = "username" value = "sa" />
    < property name = "password" value = "sa" />
</ bean >
   
< bean id = "mySessionFactory"
class = "org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
    < property name = "dataSource" ref = "dataSource" />
    < property name = "mappingResources" >
      < list >
        < value > product.hbm.xml </ value >
      </ list >
    </ property >
    < property name = "hibernateProperties" >
      < value >
        hibernate.dialect=org.hibernate.dialect.MySQLDialect
      </ value >
</ property >
</ bean >
public class HibernateDAO extends HibernateDaoSupport {
    public void save(User uaer){
        this .getHibernateTemplate().save(user);
    }
}
在代码清单 1 中咱们定义了一个数据源而且经过这个数据源咱们建立了一个 Hibernate SessionFactory ,经过 Spring SessionFactory 注入进 HibernateDAO ,在 save 方法中调用 HibernateTemplate save 方法将 User 对象持久化入数据库。