首页 > 代码库 > Spring JDBC
Spring JDBC
为了避免持久化的逻辑分散到应用的各个组件中,将数据访问功能放到一个或多个专注于此项任务的组件中,这样的组件通常称为数据访问对象(DAO)或Repository。
为了避免应用与特定的数据访问策略耦合在一起,编写良好的Repository应该以借口的方式暴漏功能。通过接口来访问Repository可以为这些数据访问接口创建mock实现,提升单元测试的效率。
SQLException表示在尝试访问数据库时出现了问题,但这个异常却没有告诉你哪里出错了以及如何进行处理。
可能导致抛出SQLException的常见问题包括:应用程序无法连接数据库;要执行查询存在语法错误;查询中所使用的表/列不存在和试图插入或更新的数据违反了数据库约束。事实上,大多数抛出SQLException的情况是致命的错误。即使对某些SQLException有处理方案,还是要捕获SQLException并查看其属性才能获知问题根源的更多信息。这是因为SQLException被视为处理数据访问所有问题的通用一场。
Spring JDBC提供的数据访问异常体系提供了多个数据访问异常,分别描述了他们抛出时所对应的问题。而且它并没有与特定的持久化方式相关联,这意味着可以使用Spring抛出一致的异常而不用关心所选择的持久化方案。Spring JDBC异常都继承自DataAccessException。DataAccessException是一个非检查型异常,因此不用捕获Srping所抛出的数据访问异常。
模板方法将过程中与特定实现相关的部分委托给接口,而这个接口的不同实现定义了过程中的具体行为。
Spring将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板(template)和回调(callback)。模板管理过程中固定的部分(书屋控制,管理资源以及处理异常),而回调处理自定义的数据访问代码(应用程序相关的数据访问——语句、绑定参数以及整理结果集)。
Spring提供的数据访问模板,分别适用于不同的持久化机制:
jca.cci.core.CciTemplate JCA CCI连接
jdbc.core.JdbcTemplate JDBC连接
jdbc.core.namedparam.NamedParameterJdbcTemplate 支持命名参数的JDBC连接
jdbc.core.simple.SimpleJdbcTemplate 通过Java5简化后的JDBC连接
orm.hibernate3.HibernateTemplate Hibernate 3.x以上的Session
orm.ibatis.SqlMapClientTemplate iBatis SqlMap客户端
orm.jdo.JdoTemplate Java数据对象实现
orm.jpa.JpaTempalte Java持久化API的实体管理器
Spring提供了在Spring上下文中配置数据源bean的多种方式,包括:通过JDBC驱动程序定义的数据源;通过JNDI查找的数据源和连接池的数据源。也可以使用Apache Commons DBCP、c3p0和BoneCP这些框架来配置Spring的数据源
使用DBCP配置数据源
基于java的配置
@Bean public BasicDataSource dataSource(){ BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:tcp://localhost/..."); dataSource.setUsernname("username"); dataSource.setPassword("root"); dataSource.setInitialSize(5); dataSource.setMaxActive(10); return dataSource }
基于xml的配置
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" p:driverClassName="org.h2.Driver" p:url="jdbc:h2:tcp://localhost/" p:username="username" p:password="root" p:initialSize="5" p:maxActive="10" />
DBCP BasicDataSource一些常用的池配置属性
initialSize 池启动时创建的连接数量
maxActive 同以时间可以从池中分配的最多连接数,若为0,则表示无限制
madIde 池里不会被释放的最多空闲连接数,若为0,则表示无限制
maxOpenPreparedStatements 在同一时间能够从语句池中分配的预处理语句的最大数量,若为0,则表示无限制
maxWait 在抛出异常之前,池等待连接回收的最大时间,若设置为-1,表示无限等待
minEvictabelIdeTimeMills 连接在池中保持空闲而不被回收的最大时间
minIde 在不创建新连接的情况下,池中保持空闲的最小连接数
poolPreparedStatements 是否对预处理语句进行池管理
在Spring中,通过JDBC驱动定义数据源是最简单的配置方式。Spring提供了三个这样的数据源类供选择:
DriverManagerDataSource:在每个连接请求时都会返回一个新建的连接。与DBCP的BasicDataSource不同,由DriverManagerDataSource提供的连接并没有进行池化管理
SimpleDriverDataSource:与DriberManagerDataSource的工作方式类似,但是它直接使用JDBC驱动,来解决在特定环境下的类的加载问题,如OSGi容器
SingleConnectionDataSource:在每个连接强求时都会返回同一个的连接。尽管SingleConnectionDataSource不是严格意义上的连接池数资源,但可以视其为自由一个连接的池
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="driverClassName" p:url="jdbc:..." p:username="username" p:passord="" />
@Bean public DataSource dataSource(){ DriverManagerDataSource dataSource =new DriverManagerDataSource(); dataSource.setDriverClassName("driverClassName"); dataSource.setUrl("url"); dataSource.setUsername("username"); dataSource.setPassword("password"); return dataSource; }
嵌入式数据库(embedded database)作为应用的一部分运行,而不是应用连接的独立数据库服务器。Spring的jdbc命名空间能够简化嵌入式数据库的配置
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http:///www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd " > <jdbc:embedded-datatbase id="dataSource" type="H2"> <jdbc:script location="" /> <jdbc:script location="" /> </jdbc:embedded-database> </beans>
@Bean public DataSource dataSource(){ return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:*.sql") .build(); }
可以将不同的profile配置在不同的数据源中
package cherry.config; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jndi.JndiObjectFactoryBean; @Configuration public class DataSourceConfiguration { @Profile("development") @Bean public DataSource embeddedDataSource(){ return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); } @Profile("qa") @Bean public DataSource dataSourceForQA(){ BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("driverName"); dataSource.setUrl("url"); dataSource.setUsername("username"); dataSource.setPassword("password"); dataSource.setInitialSize(5); dataSource.setMaxActive(10); return dataSource; } @Profile("production") @Bean public DataSource dataSource(){ JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("jdbc/databaseName"); jndiObjectFactoryBean.setResourceRef(true); jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class); return (DataSource)jndiObjectFactoryBean.getObject(); } }
Spring JDBC将数据访问的样板代码抽象到模板类之中。Spring为JDBC提供了三个模板类供选择:
JdbcTemplate: 最基本的Spring JDBC模板,这个模板支持简单的JDBC数据访问功能以及基于索引参数的查询
NamedParameterJdncTemplate:使用该模板类执行查询时可以将值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数
使用JdbcTemplate只需要为其设置DataSource即可
@Bean
public JdbcTemplate jdbcTempalte(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
将jdbcTemplate装配到Respository中.JdbcOperations是一个接口,定义了JdbcTemplate所实现的操作
@Repository
public class RepositoryImpl implements Respostory{
private JdbcOperations jdbcOperations;
@Inject
public RepositoryImpl(JdbcOperations jdbcOperations){
this.jdbcOperations = jdbcOperations;
}
}
调用JdbcTemplate.update()方法时会获取连接、创建语句并执行插入SQL;findOne()方法使用了JdbcTemplate的回调;queryForObject()方法从数据库查询,它有三个参数:String(查询数据的sql),rowMapper(从ResultSet中提取数据并构建对象)和可变参数列表(要绑定到查询上的索引参数值)
命名参数可以赋予SQL中每个参数一个明确的名字,在绑定只到查询语句的时候就通过该名字来引用参数。使用命名参数查询,绑定只的顺序就不重要了。如果查询语句发生了变化导致参数的顺序与之前不一致,也扔不需要修改绑定的代码。
@Bean public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource){ return new NamedParameterJdbcTemplate(dataSource); } public void addSpitter(Spitter spitter){ private static final String INSER_SPITTER = "insert into spitter(username, password, email) values(:username, :password, :email)"; Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("username", spitter.getUsername()); paramMap.put("password", spittler.getPassword()); paramMap.put("email", spitter.getEmail()); jdbcOperations.update(INSER_SPITTER, paramMap); }
Spring JDBC