1、统一的异常体系
统一的异常体系是整合不同的持久化实现技术的关键,spring提供了一套和实现技术无关的、面向DAO层语义的异常体系,并
通过转换器将不同持久化技术的异常转换成Spring的异常。
1.1、Spring的DAO异常体系
(1)Spring在org.springframework.dao包中提供了一套完备优雅的DAO异常体系,这些异常都继承于DataAccessException,而DataAccessException又继承于NestedRuntimeException,NestedRuntimeException以嵌套的方式封装了异常源,用户可以方便地通过
getCause()方法获取原始的异常信息。
如下是DAO异常层次的第一层:
(2)spring的这个异常体系具体高度的可扩展性,当spring需要对一个新的持久化技术提供支持时,只要为其定义一个对应的子异常就可以了。
比如spring扩展类Hibernate和TopLink
的数据访问异常,如图:
1.2、JDBC的异常转换器
(1)传统的JDBC API总是抛出
SQLExcepton异常,这个异常的2个属性一个返回数据库相关的错误码,一个返回String类型SQL状态码。Spring根据这2个信息将其转换为对应的异常。在
org.springframework.jdbc.support包中定义了
SQLExceptionTranslator接口,这个接口的2个子类:
SQLErrorCodeSQLExceptionTranslator和
SQLStateSQLExceptionTranslator替我们完成了这个转换工作。
1.3、其他持久化技术的异常转换器
(1)各持久化异常转换器如下:
这些工具类除了具有异常转换的功能外,还提供了从事务上下文中返回相同会话的功能。
Spring也支持ibatis持久化技术,由于ibatis抛出的异常是和JDBC相同的SQLException异常,所以直接采用和JDBC相同的异常转换器。
2、统一数据访问模板
(1)spring将相同的数据访问流程(比如获取连接、开启事务、异常事务回滚、关闭资源、处理异常)等固化到模板类中,并将数据访问中固定和变化的部分分开,同时保证模板类是线程安全的,以便多个数据访问线程共享同一模板实例。
固定的部分在模板类中已经准备好,而变化的部分通过回调接口开放出来,下图描述了模板类是如何拆分固定和变化部分的逻辑:
(2)Spring为不同持久化技术所提供的模板类
3、数据源
不管何种持久化技术,都必须拥有数据连接,在Spring中,数据连接是通过数据源获得的。在以往的应用中,数据源一般是Web应用服务器提供的。在Spring中,获取数据源有3种方式:
- 通过JNDI获取应用服务器的数据源;
- 直接在Spring容器中配置数据源;
- 通过代码方式创建数据源。
3.1、配置一个数据源
(1)Spring在第三方依赖包中包含了两个数据源的实现类包:
- 其一是Apache的DBCP;
- 其二是C3P0。
(2)
DBCP数据源
DBCP是一个依赖commons-pool对象池机制的数据库连接池,所以在类路径下还必须包括commons-pool的类包。下面是使用DBCP配置MySql数据源的片段:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destory-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://数据库服务器ip:端口/数据库实例名"
p:username="数据库用户名"
p:password="密码"/
>
BasicDataSource提供了close()方法关闭数据源,所以必须设定destory-method="close"属性,以便Spring容器关闭时,数据源能够正常关闭。
除了以上必需的参数外,还有其他一些常用的属性:
(3)C3P0数据源
C3P0是一个开放源代码的JDBC数据源实现项目,实现了JDBC3和JDBC2扩展规范说明的Connection和Statement池。下面使用C3P0配置一个数据源:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" sfd
p:driverClassName="com.mysql.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://数据库服务器ip:端口/数据库实例名"
p:use="数据库用户名"
p:password="密码"/
>
C3P0拥有比DBCP更丰富的配置属性,通过这些属性,可以对数据源进行各种有效的控制,属性如下:
3.2、获取JNDI数据源
(1)如果希望使用服务器提供的数据源,Spring专门为此提供了引用JNDI数据源的JndiObjectFactoryBean类,下面是一个简单的配置:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
p:jndiName="java:comp/env/服务器中配置的数据源的名称"/>
(2)Spring为获取JavaEE资源提供了一个jee命名空间,下面是使用jee命名空间引用JNDI数据源的配置示例:
3.3、Spring的数据源实现类
Spring本身也提供了一个简单的数据源实现类DriverManagerDataSource,它位于org.springframework.jdbc.datasource包中。这个类实现了javax.sql.DataSource接口,但它并没有提供池化连接的机制,每次调用getConnection()获取新连接时,只是简单地创建一个新的连接。
如下是DriverManagerDataSource的简单使用: