在看《pro spring》,看到第八章感觉有点乱。第一例子就开始需要的两个域就没有。对Spring对JDBC的支持原理,以及对样例代码的解释也不够详细。所以自己尝试总结下。
一、传统的JDBC的应用
学习一项新应用,我首先应该是先了解下老的技术是怎样实现的,是什么原因促使新技术的产生,无疑是真正理解一项技术之根本。
一般书籍或手册在介绍自身数据库应用技术时都给了传统的JDBC应用代码,并真对代码进行分析。在这里先不举类似例子了,只把其结论罗列一下。
1. 指定数据库连接参数
2. 打开数据库连接
3. 生命SQL语句
4. 预编译并执行SQL语句
5. 遍历查询结果(如果需要的话)
6. 处理每一次遍历操作
7. 处理抛出的任何异常
8. 处理事务
9. 关闭数据库连接
总之,JDBC的缺点就时太麻烦了,不易编码,容易出错,不利于开发者把精力投入到业务上去。简化JDBC就是新技术的目标。象Spring,hibernate等都通过对JDBC进行封装,以达到简化开发的目的。但是这些技术在自身侧重上略有不同。如Hibernate主要进行Object/Relational Mapping。
二 spring如何封装的JDBC
Spring JDBC包结构
Spring JDBC抽象框架由四个包构成:core、dataSource、object以及support。
JdbcTemplate类
JdbcTemplate是core包的核心类。它的功能有:
管理资源的创建和释放工作
管理JDBC核心处理流程,比如SQL语句的创建、执行。
对ResultSet进行遍历并加以提取。
调用存储过程
捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。
我们该怎么用JdbcTemplate?使用JdbcTemplate进行编码只需要根据明确定义的一组契约来实现回调接口。
JdbcTemplate的实例化时,构造方法要求传递数据源。一般有两种用法:第一种是把DataSource bean 注入到一个service类中,然后把这个DataSource属性,传递给JdbcTemplate的构造函数来实例化。第二种是在配置文件中,把DataSource bean传递给JdbcTemplate bean。
JdbcTemplate主要方法:
1)执行SQL语句
JdbcTemplate jdbcTemplate;//获得方法从略
jdbcTemplate.execute("create table user (id integer, username varchar(20))");
2)执行查询 JdbcTemplate提供了非常丰富的查询方法。记忆应该从业务出发,通过查找api得到适当的方法。不断积累的过程中就记住了。
name="code">
JdbcTemplate jdbcTemplate;//获得方法从略
int count =jdbcTemplate.querForInt("select count(*) from user");
List rows = jdbcTemplate.queryForList("select * from mytable");
3)更新
JdbcTemplate jdbcTemplate;//获得方法从略
jdbcTemplate.update("update mytable set name = ? where id = ?", new Object[] {name, new Integer(id)});
4)写入
JdbcTemplate使用了好几种回调接口来向数据库写数据。先来看两个比较简单的接口。
PreparedStatementCreator接口,这个接口的实现者时负责创建PrepareStatement。这个接口提供了一个方法:
PrepareStatement createPreparedStatement(Connection conn) throw SQLException;
实现这个接口时,要负责从Connection参数创建并返回一个PreparedStatement,但不须考虑异常处理。
NamedParameterjdbcTemplate
NamedParameterJdbcTemplate类增加了在SQL语句中使用命名参数的支持。在此之前,在传统的SQL语句中,参数都是用' ?' 占位符来表示的。NameparameterJdbcTemplate类内部封装了一个普通的JdbcTemplate,并作为其代理来完成大部分工作。
NamedParameterjdbcTemplate类是线程安全的,该类的最佳使用方式不是每次操作的时候都实例化一个新的NamedParameterjdbcTemplate,而是针对每个DataSource只配置一个NamedParameterjdbcTemplate实例(比如在Spring IoC容器中使用Spring Ioc来进行配置),然后在那些使用该类的DAO中共享该实例。
注意: NamedParameterJdbcTemplate类内部包装了一个标准的JdbcTemplate类。如果需要访问其内部的JdbcTemplate实例(比如访问JdbcTemplate的一些方法)那么你需要使用getJdbcOperations()方法返回的JdbcOperations接口。(JdbcTemplate实现了JdbcOperations接口)。
SimpleJdbcTemplate
注意:该类所提供的功能仅使用于Java 5
SimpleJdbcTemplate类是JdbcTemplate类的一个包装起(wrapper),它利用了Java 5的一些语言特性,比如Varargs和Autoboxing。对那些习惯了Java 5 的程序员,这些新的语言特性还是很好用的。
下面两端代码是JdbcTemplate-style和SimpleJdbcTemplate-style实现同一个功能
//JdbcTemplate-style
public Actor findActor(long id) {
Sring sql = "select id, first_name,last_name from T_ACTOR where id = ?“;
RowMapper mapper = new RowMapper(){
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Actor actor = new Actor();
actor.setId(rs.getLong(Long.valueOf(rs.getLong("i"))));
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
}
//正常应该注入
JdbcTemplate jdbcTemplate = new JdbcTemplate(this.getDataSource());
return (Actor) jabcTemplate.queryForObject(sql, mapper, new Object[] {Long.valueOf(id)});
}
//SimpleJdbcTemplate-stale
public Actor findactor(long id) {
String sql = "select id,first_name, last_name from T_ACTOR where id = ? ";
ParameterizedRowMapper<Actor> mapper = new ParameterizedRowMapper<Actor>() {
public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {
Actor actor = new Actor();
actor.setId(rs.getLong("id"));
actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
return actor;
}
}
SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(this.getDataSource());
return simpleJdbcTemplate.queryForObject(sql, mapper, id);
}
数据源
对了对数据库执行JDBC操作,都必须有一个Connection, 在Spring的DAO框架里,Connection对象是通过DataSource获得的。在使用Spring JDBC时,你既可以通过JNDI获得数据源,也可以自行配置数据源(如使用Spring提供的DataSource实现类)。使用后者可以更方便的脱离Web容器来进行单元测试。
这里先简单看一下DriverManagerDataSource,不过DataSource有多种实现。使用DriverManagerDataSource和以前用JDBC类连接没什么两样。实际应用Spring应该通过配置文件加载DataSource,后面会介绍实际配置方法。
DrviverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jabcDriver");
dataSource.setUrl("jdbc:hsqldb:hsql://localhost:");
dataSource.setUername("sq");
dataSource.setPassword("");
我来具体看看都有那些DataSource类: DataSourceUtiles类
DataSourceUtiles作为一个帮助类提供易用且强大的数据库访问能力,可以使用该类提供的静态方法从JNDI获取数据库连接以及在必要时候关闭之。 它提供支持线程绑定的数据库连接(比如使用DataSourceTransactionManager 的时候,把数据库连接绑定到当前的线程上)。
注:getDataSourceFromJndi(...)方法主要用于那些没有使用bean factory或者application context的场合。
SmartDataSource接口
AbstractDataSource类
SingleConnectionDataSource类
DriverManagerDataSource类
TransactionAwareDataSourceProxy类
DataSourceTransactionManager类
异常处理
因为Spring提倡使用运行期异常而不是检查异常,所以它通过一种机制把检测到已检查异常转译成运行期异常。在这里就是把SQLException转换成Spring JDBC异常。因为Spring的SQL异常是运行期异常,它们的控制粒度要比已检查异常要细的多。
spring的异常转换
spring提供了SQLExceptionTranslator接口的默认实现,可以把通用SQL错误编码翻译成Spring JDBC异常。在大多数情况下,这个实现足够用了。不过仍然可以扩展Spring的默认实现,让JdbcTemplate使用新的SQLExceptionTranslator。
用Java对象来表达JDBC操作
org.springframework.jdbc.object包下的类允许用户更加面向对象的方式访问数据库。比如说,用户可以执行查询并返回一个list, 该list作为一个结果集将把从数据库中取出来的列数据映射到业务对象的属性上。用户也可以执行存储过程。
SqlQuery类
MappingSqlQuery类
SqlUpdate类
StoredProcedure类