一、Spring数据访问模板
Spring提供的数据访问模板,分别适用于不同的持久化机制。
模板类(org.springframework.*) | 用途 |
---|---|
jca.cci.core.CciTemplate | JCA CCI连接 |
jdbc.core.JdbcTemplate | JDBC连接 |
jdbc.core.namedparam.NamedParameterJdbcTemplate | 支持命名参数的JDBC连接 |
jdbc.core.simple.SimpleJdbcTemplate | 通过Java 5简化后的JDBC连接(Spring 3.1中已经废弃) |
orm.hibernate3.HibernateTemplate | Hibernate 3.x以上的Session |
orm.ibatis.SqlMapClientTemplate | iBATIS SqlMap客户端 |
orm.jdo.JdoTemplate | Java数据对象(Java DataObject)实现 |
orm.jpa.JpaTemplate | Java持久化API的实体管理器 |
二、配置数据源
2.1 使用JNDI数据源
1) 在xml中配置
利用Spring,我们可以像使用Spring bean那样配置JNDI中数据源的引用并将其装配到需要的类中。位于jee命名空间下的<jee:jndi-lookup>元素可以用于检索JNDI中的任何对象(包括数据源)并将其作为Spring的bean。例如,如果应用程序的数据源配置在JNDI中,我们可以使用<jee:jndi-lookup>元素将其装配到Spring中,如下所示:
其中jndi-name属性用于指定JNDI中资源的名称。如果只设置了jndi-name属性,那么就会根据指定的名称查找数据源。但是,如果应用程序运行在Java应用服务器中,你需要将resource-ref属性设置为true,这样给定的jndi-name将会自动添加“java:comp/env/”前缀。
2)在Java中配置
如果想使用Java配置的话,那我们可以借助JndiObjectFactoryBean从JNDI中查找DataSource:
2.2 使用数据源连接池
尽管Spring并没有提供数据源连接池实现,但是我们有多项可用的方案,包括如下开源的实现:
- Apache Commons DBCP (http://jakarta.apache.org/commons/dbcp);
- c3p0 (http://sourceforge.net/projects/c3p0/ );
- BoneCP( http://jolbox.com/ )。
1) xml中配置
这些连接池中的大多数都能配置为Spring的数据源,在一定程度上与Spring自带的DriverManagerDataSource或SingleConnectionDataSource很类似(我们稍后会对其进行介绍)。例如,如下就是配置DBCP BasicDataSource的方式:
2)在java中配置
前四个属性是配置BasicDataSource所必需的。属性driverClassName指定了JDBC驱动类的全限定类名。在这里我们配置的是H2数据库的数据源。属性url用于设置数据库的JDBCURL。最后,username和password用于在连接数据库时进行认证。
以上四个基本属性定义了BasicDataSource的连接信息。除此以外,还有多个配置数据源连接池的属性。下表列出了DBCPBasicDataSource最有用的一些池配置属性:
池配置属性 | 所指定的内容 |
---|---|
initialSize | 池启动时创建的连接数量 |
maxActive | 同一时间可从池中分配的最多连接数。如果设置为0,表示无限制 |
maxIdle | 池里不会被释放的最多空闲连接数。如果设置为0,表示无限制 |
maxOpenPreparedStatements | 在同一时间能够从语句池中分配的预处理语句(preparedstatement)的最大数量。如果设置为0,表示无限制 |
maxWait | 在抛出异常之前,池等待连接回收的最大时间(当没有可用连接时)。如果设置为-1,表示无限等待 |
minEvictableIdleTimeMillis | 连接在池中保持空闲而不被回收的最大时间 |
minIdle | 在不创建新连接的情况下,池中保持空闲的最小连接数 |
poolPreparedStatements | 是否对预处理语句(prepared |
2.3 基于JDBC驱动的数据源
在Spring中,通过JDBC驱动定义数据源是最简单的配置方式。Spring提供了三个这样的数据源类(均位于org.springframework.jdbc.datasource包中)供选择:
- DriverManagerDataSource:在每个连接请求时都会返回一个新建的连接。与DBCP的BasicDataSource不同,由DriverManagerDataSource提供的连接并没有进行池化管理;
- SimpleDriverDataSource:
与DriverManagerDataSource的工作方式类似,但是它直接
使用JDBC驱动,来解决在特定环境下的类加载问题,这样的环
境包括OSGi容器;- SingleConnectionDataSource:在每个连接请求时都会返回同一个的连接。尽管SingleConnectionDataSource不是严格意义上的连接池数据源,但是你可以将其视为只有一个连接的池。
1) 使用java配置
2)使用xml配置
与具备池功能的数据源相比,唯一的区别在于这些数据源bean都没有提供连接池功能,所以没有可配置的池相关的属性。
尽管这些数据源对于小应用或开发环境来说是不错的,但是要将其用于生产环境,你还是需要慎重考虑。因为SingleConnectionDataSource有且只有一个数据库连接,所以不适合用于多线程的应用程序,最好只在测试的时候使用。而DriverManagerDataSource和SimpleDriverDataSource尽管支持多线程,但是在每次请求连接的时候都会创建新连接,这是以性能为代价的。鉴于以上的这些限制,我强烈建议应该使用数据源连接池。
2.4 使用嵌入式的数据源
嵌入式数据库作为应用的一部分运行,而不是应用连接的独立数据库服务器。尽管在生产环境的设置中,它并没有太大的用处,但是对于开发和测试来讲,嵌入式数据库都是很好的可选方案。这是因为每次重启应用或运行测试的时候,都能够重新填充测试数据。
Spring的jdbc命名空间能够简化嵌入式数据库的配置。例如,如下的程序清单展现了如何使用jdbc命名空间来配置嵌入式的H2数据库,它会预先加载一组测试数据。
1)使用jdbc命名空间配置嵌入式数据库
我们将<jdbc:embedded-database>的type属性设置为H2,表明嵌入式数据库应该是H2数据库(要确保H2位于应用的类路径下)。另外,我们还可以将type设置为DERBY,以使用嵌入式的ApacheDerby数据库。
在<jdbc:embedded-database>中,我们可以不配置也可以配置多个<jdbc:script>元素来搭建数据库。程序清单10.1中包含了两个<jdbc:script>元素:第一个引用了schema.sql,它包含了在数据库中创建表的SQL;第二个引用了test-data.sql,用来将测试数据填充到数据库中。
除了搭建嵌入式数据库以外,<jdbc:embedded-database>元素还会暴露一个数据源,我们可以像使用其他的数据源那样来使用它。在这里,id属性被设置成了dataSource,这也是所暴露数据源的bean ID。因此,当我们需要javax.sql.DataSource的时候,就可以注入dataSource bean。
2) 使用java配置
可以看到,setType()方法等同于<jdbc:embedded-database>元素中的type属性,此外,我们这里用addScript()代替<jdbc:script>元素来指定初始化SQL。
三、在Spring中使用JDBC
Spring的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需编写从数据库读写数据的必需代码。
正如前面小节所介绍过的,Spring将数据访问的样板代码抽象到模板类之中。Spring为JDBC提供了三个模板类供选择:
- JdbcTemplate:最基本的Spring JDBC模板,这个模板支持简单的JDBC数据库访问功能以及基于索引参数的查询;
- NamedParameterJdbcTemplate:使用该模板类执行查询时可以将值以命名参数的形式定到SQL中,而不是使用简单的索引参数;
- SimpleJdbcTemplate:该模板类利用Java 5的一些特性如自动装箱、泛型以及可变参数列表来简化JDBC模板的使用。
以前,在选择哪一个JDBC模板的时候,我们需要仔细权衡。但是从Spring 3.1开始,做这个决定变得容易多了。SimpleJdbcTemplate已经被废弃了,其Java 5的特性被转移到了JdbcTemplate中,并且只有在你需要使用命名参数的时候,才需要使用NamedParameterJdbcTemplate。这样的话,对于大多数的JDBC任务来说,JdbcTemplate就是最好的可选方案,这也是本小节中所关注的方案。
3.1 使用JdbcTemplate来插入数据
为了让JdbcTemplate正常工作,只需要为其设置DataSource就可以了,这使得在Spring中配置JdbcTemplate非常容易,如下面的@Bean方法所示:
在这里,DataSource是通过构造器参数注入进来的。这里所引用的dataSourcebean可以是javax.sql.DataSource的任意实现。
我们可以将jdbcTemplate装配到Repository中并使用它来访问数据库。例如SpitterRepository使用了JdbcTemplate:
在这里,JdbcSpitterRepository类上使用了@Repository注解,这表明它将会在组件扫描的时候自动创建。它的构造器上使用了@Inject注解,因此在创建的时候,会自动获得一个JdbcOperations对象。JdbcOperations是一个接口,定义了JdbcTemplate所实现的操作。通过注入JdbcOperations,而不是具体的JdbcTemplate,能够保证JdbcSpitterRepository通过JdbcOperations接口达到与JdbcTemplate保持松耦合。
作为另外一种组件扫描和自动装配的方案,我们可以将JdbcSpitterRepository显式声明为Spring中的bean,如下所示:
插入数据
读取数据
3.2 NamedParameterJdbcTemplate
1) 使用命名参数
名参数可以赋予SQL中的每个参数一个明确的名字,在绑定值到查询语句的时候就通过该名字来引用参数。例如,假设SQL_INSERT_SPITTER查询语句是这样定义的:
使用命名参数查询,绑定值的顺序就不重要了,我们可以按照名字来绑定值。如果查询语句发生了变化导致参数的顺序与之前不一致,我们不需要修改绑定的代码。
2) NamedParameterJdbcTemplate
NamedParameterJdbcTemplate是一个特殊的JDBC模板类,它支持使用命名参数。在Spring中,NamedParameterJdbcTemplate的声明方式与常规的JdbcTemplate几乎完全相同:
在这里,我们将NamedParameterJdbcOperations(NamedParameterJdbcTemplate
所实现的接口)注入到Repository中,用它来替代JdbcOperations。现在的addSpitter()方法如下所示: