Spring 的JDBC模板方法
Spring 通过模板方法模式,帮助程序员完成资源创建,资源管理等固定的的工作。程序员可专注于编写sql语句,处理结果集 。
JDBCTemplate 有一个DataSource 类型的成员变量为其创建所需要的连接资源 。
JdbcTemplate t = new JdbcTemplate( DataSource ) ;
t.update( …. ) ;
t.query( …. ) ;
DataSource的使用 :
Spring 提供几种选择来获得DataSource对象 :
1,通过 JNDI
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/myDataSource</value>
</property>
</bean>
2,创建DataSource连接池(应用没有运行在AppServer中)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value></value>
</property>
<property name="url">
<value></value>
</property>
<property name="username">
<value></value>
</property>
<property name="password">
<value></value>
</property>
</bean>
3,测试时使用的DataSource
Spring提供了一个简易的DataSource,由于在单元测试时使用 。
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDrverClassName( xxx ) ;
ds.setUrl( url ) ;
ds.setUserName( username ) ;
ds.setPassword( password ) ;
在DAO中使用JdbcTemplate :
基本步骤 :
1) 声明dataSource
2) 声明JdbcTemplate,向JdbcTemplate中注入dataSource
3) 声明Dao对象,并向dao对象中注入JdbcTemplate,JdbcTemplate是线程安全的,所以对同一个DataSource对象,使用一个JdbcTemplate就可以了。
4) 在Dao对象中使用JdbcTemplate进行JDBC编程 。
声明DataSource 对象 。
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value></value>
</property>
<property name="url">
<value></value>
</property>
<property name="username">
<value></value>
</property>
<property name="password">
<value></value>
</property>
</bean>
声明JdbcTemplate,向JdbcTemplate中注入dataSource
<bean id=”jdbcTemplate” class=”org.springframework.jdbc.core.JdbcTemplate”>
<property name=”dataSource”>
<ref bean=”dataSource”/>
</property>
</bean>
声明Dao对象,并向dao对象中注入JdbcTemplate,JdbcTemplate
<bean id=”dao” class=”xxxxx.StudentDao>
<property name=”jdbcTemplate”>
<ref bean=”jdbcTemplate”/>
</property>
</bean>
在Dao对象中使用JdbcTemplate进行JDBC编程
public class StudentDao{
private JdbcTemplate jdbcTemplate ;
public void setJdbcTemplate( JdbcTemplate jdbcTemplate ){
this.jdbcTempldate = jdbcTemplate ;
}
Public JdbctTemplate getJdbcTemplate(){ return jdbcTemplate ; }
public void insert( Persion person ){
String sql = “insert into Person(….) values ( ? , ? , ? ) ;
Object args[] = { person.getId() , person.getName() , person.getGender() } ;
jdbcTemplate.update( sql , args ) ;
}
}
jdbcTempldate.update()方法还有一种重载,多一个int[] 由于指定每一个参数的数据类型,
当参数中有null的时候,这个重载会提供更好的支持 。
String sql = “insert into …. “ ;
Object args[] = { ……. } ;
int types[] = { Types.INTEGER , TYPE.VARCHAR , TYPE.VARCHAR } ;
jdbcTemplate.update( sql , args , types ) ;
使用Batch提高性能
JdbcTemplate中提供了batchUpdate方法来利用Batch提高性能 。
jdbcTemplate.batchUpdate( sql , setter ) ;
该函数需要一个BatchPreparedStatementSetter 类型的一个参数,每次添加一个Batch之后,jdbcTempldate都会调用setter的setValue方法,为当前SQL设置SQL 参数。如果我们要使用Batch特性的话,需要自己实现该接口 。
BatchPreparedStatementSetter接口的声明是 :
public interface BachPreparedStatementSetter{
int getBatchSize()
/**
*@index 用来指定当前是第几次调用setValues方法,或者也可以
* 理解为是在为第几个Bath设置参数 。
*/
void setValues( PreparedStatement pstm , int index ) ;
}
我们自己实现的BatchPreparedStatementSetter :
Public class MyBatchPreparedStatementSetter(
private List persons ;
// getPersons and setPersons ;
Public int getBatchSize(){ return person.size() ; }
Public void setValue( PreparedStatement pstm , int idx ){
Person p = (Person)persons.get( idx ) ;
Pstm.setInt( 1, p.getId() ) ;
Pstm.setString( 2 , p.getName ) ;
………
}
}
JdbcTemplate中使用到的回调接口 :
在JdbcTemplate工作的过程中,要使用到很多回调接口,对于这些接口,Spring都提供了相应得实现。
1,PreparedStatementCreator .
public interface PreparedStatementCreator( Connection conn ){
PreparedStatement createPreparedStatement( Connection conn ) throws SQLException
}
该接口用于创建PreparedStatement对象。JdbcTemplate 在执行sql所需要用到的statement就是通过这个接口创建的。
2, SqlProvider :
在实现PreparedStatementCreator的同时,通常都会实现SqlProvider接口 , 该接口的getSql()方法可以向JdbcTemplate类提供SQL语句的字符串。
public interface SqlProvider(){
String getSql();
}
3, PreparedStatementSetter 是PreparedStatementCreator的补充,实现这个接口的类将
接受到一个PreparedStatement ,然后负责为他设置参数
public interface PreparedStatementSetter{
void setValues( PreparedStatement pstm ) throws SQLException ;
}
我们传递个JdbcTemplate的sql参数就是通过这个接口设置到PreparedStatement中去的。
public class MySetter implements PreparedStatementSetter{
private Student student = null ;
public void setStudent( Student student ){ this.student = student ; }
public Student getStudent(){ return this.student ; }
public void setValues( PreparedStatement pstm ) throws ....{
pstm.setInt( 1 , student.getId() ) ;
pstm.setString( 2 student.getName() ) ;
......
}
}
数据查询.
任何查询都需要通过ResultSet获得查询结果,我没只需通过一个回调接口
来告诉Spring如何处理结果集就可以了 。
public interface RowCallBackHandler{
void processRow( ResultSet rs ) ;
}
当我们的查询需要返回多个结果的时候, 我们可以利用Spring提供的RowMappResultReader 他负责将结果集中的数据封装到一个List中,但是在使用RowMapResultReader时我们需要提供一个RowMapper接口的实现, RowMapper接口是RowMapResultReader要使用的一个工具负责把一条记录封装到一个对象中 ,
public interface RowMapper{
public Object mapRow( ResultSet rs ,int idx );
}
在RowMappResultReader中会循环调用RowMapper的mapRow方法,
从而获得一个List
Public List getAllPerson(){
String sql = “select …….. “ ;
Object args = null ;
List ret = null ;
ret =JdbcTemplate.query( sql , args , new RowMappResultReader( new myRowMapper ) ) ;
return ret ;
}
public class MyRowMapper implements RowMapper{
public Object mapRow( ResultSet rs ,int idx ){
Person p = new Person();
p.setName( rs.getString(1) );
p.setAge( rs.getInt(2) );
return p ;
}
}
Spring中的数据访问异常体系
Spring 提供了一套分级的异常体系 。
Spring的DAO没有抛出任何与特定技术细节相关的异常。 所抛出的都是
org.springframework.dao.DataAccessException 及其子类 ,DataAccessException
是RuntimeException的子类,所以可以不被处理 , 由于这些异常通常都是不可恢复的
所以不强制我们去处理他们 。