第一章
Spring的数据库支持
5.1 Spring对DAO的支持<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
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
对象持久化入数据库。
我的其它Spring文章,也许会对您有帮助