第一章
Spring的数据库支持
5.1 Spring对DAO的支持
Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不一样的数据访问技术, 如JDBC,Hibernate或者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中定义的异常层次相兼容的异常。其中JDOException属unchecked异常,它们则被简单地抛出,尽管这在异常处理方面牺牲了通用的DAO抽象。
2) 一致的DAO支持抽象类
为了便于以一种一致的方式使用各类数据访问技术,如JDBC、JDO和Hibernate, 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 Spring的ORM框架支持
Spring在资源管理,DAO实现支持以及事务策略等方面提供了与 Hibernate、JDO、Oracle TopLink、iBATIS 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)
测试简单。 Spring的IoC使得替换不一样的实现和配置变得很是简单,这些内容包括:Hibernate SessionFactory
的位置,JDBC DataSource
,事务管理器以及映射对象的实现(若是须要)等。这样也就很容易隔离并测试持久化相关的代码的各个部分。
2)
异常封装。 Spring可以封装你所选择的O/R Mapping工具所抛出的异常,将它们从专有的、潜在的checked exception转化为一组抽象的runtime DataAccessException体系。这可使你仅须要在恰当的应用程序层次去处理大部分不可恢复的持久层异常,从而避免了不少使人讨厌的catch/throw以及异常声明。固然,你仍是能够在你须要的地方捕捉和处理异常。回想一下JDBC异常(包括与DB相关的Dialect)被转变为一样的异常体系,这就意味着你能够在一致的编程模型中处理JDBC操做。
3)
通用的资源管理。 Spring的application context可以处理诸如Hibernate的 SessionFactory
, JDBC的 DataSource
,iBatis的SQL 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来实现主要的应用需求一般是更好的,尤为是当你可能会由于功能、性能或其余方面的缘由而须要切换到另外一种实现的时候。举例来讲,Spring对Hibernate事务和异常抽象,容许你经过IoC机制轻松封装mapper和DAO对象来实现数据访问功能,这些特性都可以使你在 不牺牲Hibernate强大功能 的状况下在你的应用程序中隔离Hibernate的相关代码。处理DAO的高层次的service代码无需知道DAO的具体实现。这一机制能够很容易使用mix-and-match方案互不干扰地实现数据访问层(好比在一些地方用Hibernate,一些地方使用JDBC,其余地方使用iBatis), mix-and-match的特性也有利于处理遗留代码并在各类技术(JDBC、Hibernate和iBatis)之间取长补短。
咱们将首先从Hibernate开始,经过讲解Hibernate在Spring环境中的使用来阐述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
对象持久化入数据库。