第一章
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
对象持久化入数据库。
我的其它Spring文章,也许会对您有帮助
Spring的任务调度和邮件发送
Spring应用的单元测试
Spring的数据库支持
Spring的MVC框架
Spring的IoC容器
Spring对AOP的支持
Spring2.5注释驱动与基于注释的MVC