JdbcTemplate的认识和使用
Spring的JDBCTemplate
当hql等查询方式不能满足性能或灵活性的要求,必须使用SQL时,大家有三种选择:
第一、使用Hibernate 的sql 查询函数,将查询结果对象转为Entity对象。
第二、使用Hibernate Session的getConnection 获得JDBC Connection,然后进行纯JDBC API操作;
第三、选择把Spring的JDBCTemplate作为一种很不错的JDBC Utils来使用。 JDBCTemplate的使用很简单,只要在ApplicationContext文件里定义一个jdbcTemplate节点,POJO获得注入后可以直接执行操作,不需要继承什么基类,详见JDBCTemplate参考文档。
AplicationContext定义:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
实际使用:
SqlRowSet rs = jdbcTemplate.queryForRowSet(sql, params);
Tips1: jdbcTemplate有很多的ORM化回调操作将返回结果转为对象列表,但很多时候还是需要返回ResultSet,Spring有提供一个类似ResultSet的 Spring SqlRowSet对象。
Tips2:.注意jdbcTemplate尽量只执行查询操作,莫要进行更新,否则很容易破坏Hibernate的二级缓存体系。Chapter 11. 使用JDBC进行数据访问
11.1. 简介
Spring JDBC抽象框架所带来的价值将在以下几个方面得以体现:(注:使用了Spring JDBC抽象框架之后,应用开发人员只需要完成斜体字部分的编码工作。)
指定数据库连接参数
打开数据库连接
声明SQL语句
预编译并执行SQL语句
遍历查询结果(如果需要的话)
处理每一次遍历操作
处理抛出的任何异常
处理事务
关闭数据库连接
Spring将替我们完成所有单调乏味的JDBC底层细节处理工作。
11.1.1. Spring JDBC包结构
Spring JDBC抽象框架由四个包构成:core、 dataSource、object以及support。
org.springframework.jdbc.core包由JdbcTemplate类以及相关的回调接口(callback interface)和类组成。
org.springframework.jdbc.datasource包由一些用来简化DataSource访问的工具类,以及各种DataSource接口的简单实现(主要用于单元测试以及在J2EE容器之外使用JDBC)组成。工具类提供了一些静态方法,诸如通过JNDI获取数据连接以及在必要的情况下关闭这些连接。它支持绑定线程的连接,比如被用于DataSourceTransactionManager的连接。
接下来,org.springframework.jdbc.object包由封装了查询、更新以及存储过程的类组成,这些类的对象都是线程安全并且可重复使用的。它们类似于JDO,与JDO的不同之处在于查询结果与数据库是“断开连接”的。它们是在org.springframework.jdbc.core包的基础上对JDBC更高层次的抽象。
最后,org.springframework.jdbc.support包提供了一些SQLException的转换类以及相关的工具类。
在JDBC处理过程中抛出的异常将被转换成org.springframework.dao包中定义的异常。因此使用Spring JDBC进行开发将不需要处理JDBC或者特定的RDBMS才会抛出的异常。所有的异常都是unchecked exception,这样我们就可以对传递到调用者的异常进行有选择的捕获。
11.2. 利用JDBC核心类实现JDBC的基本操作和错误处理
11.2.1. JdbcTemplate类
JdbcTemplate是core包的核心类。它替我们完成了资源的创建以及释放工作,从而简化了我们对JDBC的使用。它还可以帮助我们避免一些常见的错误,比如忘记关闭数据库连接。JdbcTemplate将完成JDBC核心处理流程,比如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给我们的应用代码。它可以完成SQL查询、更新以及调用存储过程,可以对ResultSet进行遍历并加以提取。它还可以捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。
使用JdbcTemplate进行编码只需要根据明确定义的一组契约来实现回调接口。PreparedStatementCreator回调接口通过给定的Connection创建一个PreparedStatement,包含SQL和任何相关的参数。CallableStatementCreateor实现同样的处理,只不过它创建的是CallableStatement。RowCallbackHandler接口则从数据集的每一行中提取值。
我们可以在一个service实现类中通过传递一个DataSource引用来完成JdbcTemplate的实例化,也可以在application context中配置一个JdbcTemplate bean,来供service使用。需要注意的是DataSource在application context总是配制成一个bean,第一种情况下,DataSource bean将传递给service,第二种情况下DataSource bean传递给JdbcTemplate bean。因为JdbcTemplate使用回调接口和SQLExceptionTranslator接口作为参数,所以一般情况下没有必要通过继承JdbcTemplate来定义其子类。
JdbcTemplate中使用的所有SQL将会以“DEBUG”级别记入日志(一般情况下日志的category是JdbcTemplate相应的全限定类名,不过如果需要对JdbcTemplate进行定制的话,可能是它的子类名)。
11.2.2. NamedParameterJdbcTemplate类
NamedParameterJdbcTemplate类增加了在SQL语句中使用命名参数的支持。在此之前,在传统的SQL语句中,参数都是用'?'占位符来表示的。 NamedParameterJdbcTemplate类内部封装了一个普通的JdbcTemplate,并作为其代理来完成大部分工作。下面的内容主要针对NamedParameterJdbcTemplate与JdbcTemplate的不同之处来加以说明,即如何在SQL语句中使用命名参数。
通过下面的例子我们可以更好地了解NamedParameterJdbcTemplate的使用模式(在后面我们还有更好的使用方式)。
// some JDBC-backed DAO class...
public int countOfActorsByFir