Spring学习笔记(十三)-----Spring in Action
Spring的一个目标就是让你遵循对接口编程的面向对象原则。DAO的存在提供了读写数据库中数据的一种方
法。只要把这个功能通过接口暴露,应用的其他部分就可以通过这些接口访问数据库了。
在Spring的DAO框架里,Connection对象是通过DataSource获得的。
从JNDI得到DataSource,代码:
<?
xml version="1.0" encoding="UTF-8"
?>
< beans
xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" >
<!-- Spring应用经常运行在J2EE应用服务器上,或者是诸如Tomcat的Web服务器上。这些服务器都能提供的一件事:通过
JNDI获得DataSource.现在我们已经和服务器上的DataSource以及它的连接池功能连接上了。
-->
< bean id ="dataSource" class ="org.springframework.jndi.JndiObjectFactoryBean" >
< property name ="jndiName" >
< value > java:comp/env/jdbc/myDatasource </ value >
</ property >
</ bean >
<!-- 加入Spring容器运行在一个不提供DataSource的环境中,但我们还希望拥有连接池的好处,我们要实现一个DataSource
的连接池Bean,我们有了一个带连接池的DataSource,它不依赖于任何应用服务器,代码如下: -->
< bean id ="dataSource1" class ="org.apache.commons.dbcp.BasicDataSource" >
< property name ="driverClassName" >
< value > ${db.driver} </ value >
</ property >
< property name ="url" >
< value > ${db.url} </ value >
</ property >
< property name ="username" >
< value > ${db.username} </ value >
</ property >
< property name ="password" >
< value > ${db.password} </ value >
</ property >
</ bean >
</ beans >
< beans
xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" >
<!-- Spring应用经常运行在J2EE应用服务器上,或者是诸如Tomcat的Web服务器上。这些服务器都能提供的一件事:通过
JNDI获得DataSource.现在我们已经和服务器上的DataSource以及它的连接池功能连接上了。
-->
< bean id ="dataSource" class ="org.springframework.jndi.JndiObjectFactoryBean" >
< property name ="jndiName" >
< value > java:comp/env/jdbc/myDatasource </ value >
</ property >
</ bean >
<!-- 加入Spring容器运行在一个不提供DataSource的环境中,但我们还希望拥有连接池的好处,我们要实现一个DataSource
的连接池Bean,我们有了一个带连接池的DataSource,它不依赖于任何应用服务器,代码如下: -->
< bean id ="dataSource1" class ="org.apache.commons.dbcp.BasicDataSource" >
< property name ="driverClassName" >
< value > ${db.driver} </ value >
</ property >
< property name ="url" >
< value > ${db.url} </ value >
</ property >
< property name ="username" >
< value > ${db.username} </ value >
</ property >
< property name ="password" >
< value > ${db.password} </ value >
</ property >
</ bean >
</ beans >
一个模版方法定义一个流程的骨架。在我们的例子中,这个流程就是把行李从出发地运送到目的地。流程本身是固定的,不会改变。处理行李的事件顺序每一次都是一样的:检查行李、放到飞机上等等。当飞机到达目的地时,行李都被一件件的卸下来,放到传送带上,再运到行李提取处。流程是固定的,但是流程中的具体实现有些是可变的。一个模版方法将这部分可变流程的具体实现委托给一个接口,这个接口的不同实现定义了这部分流程的具体实现。
Spring把这个模式应用到数据访问上。不管我们采用什么技术,某些数据访问步骤是必须的。例如:我们总是需要和数据库建立连接,在操作完后释放资源。这就是数据访问流程中的固定步骤。但我们写的每个数据访问的实现都有略微不同,我们用不同的方式查询不同的对象、更新数据。这些就是数据访问流程中的可变步骤。
Spring把数据访问流程中的固定部分和可变部分分开,分别映射成2个截然不同的类:模版和回调。模版管理流程的固定部分,而在回调处填写你的实现细节。
在模版和回调的设计之上,每个框架都提供一个支撑类,以便让你自己的数据访问类来继承它们。这些支撑类早已拥有一个指向模版类的属性,所以不需要为每个DAO类创建这个属性。另外,每个支撑类都允许你直接得到用于跟数据库打交道的类。
模版代码使用如下:
package
com.testproject.spring.datasource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
/**/ /*
* 为了让JdbcTemplate工作,它所需要的,只是一个DataSource实例。
*/
public class StudentDaoJdbc implements StudentDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**//*
* 先从SQL语句创建一个PreparedStatement,然后绑定参数。在幕后,JdbcTemplate
* 类创建了PreparedStatementCreator和PreparedStatementSetter.这些我们都
* 不用关心,我们只管提供SQL语句和参数。还可以提供类型支持。
*/
public int insertPerson(Person person){
String sql = "insert into person(id,firstName,lastName) values(?,?,?)";
Object[] params = new Object[]{person.getId(),person.getFirstName(),person.getLastName()};
return jdbcTemplate.update(sql,params);
}
public int insertPerson2(Person person){
String sql = "insert into person(id,firstName,lastName) values(?,?,?)";
Object[] params = new Object[]{person.getId(),person.getFirstName(),person.getLastName()};
int[] types = new int[]{Types.INTEGER,Types.VARBINARY,Types.VARBINARY};
return jdbcTemplate.update(sql, params, types);
}
/**//*
* 批量更新,我们讲使用BatchPreparedStatementSetter,这个接口的2个方法
* 1、getBatchSize()告诉JdbcTemplate类有多少个语句要创建,同时也决定了要调用多少次setValues()
* 2、setValues负责创建参数
* 所以你的JDBC驱动支持批量操作,这些更新讲被批量执行,是的数据访问更高效。
*/
public int[] updatePersons(final List persons){
String sql = "insert into person(id,firstName,lastName) values(?,?,?)";
BatchPreparedStatementSetter setter = null;
setter = new BatchPreparedStatementSetter(){
public int getBatchSize(){
return persons.size();
}
public void setValues(PreparedStatement ps,int index)throws SQLException{
Person person = (Person)persons.get(index);
ps.setInt(0,person.getId().intValue());
ps.setString(1,person.getFirstName());
ps.setString(2,person.getLastName());
}
};
return jdbcTemplate.batchUpdate(sql, setter);
}
/**//*
* 当查询数据库时,我们需要通过ResultSet取得结果,Spring认识到这一步是任何查询都需要的,所以它帮助
* 我们处理了这些。取而代之,我们只需要简单的告诉Spring要怎么处理ResultSet中的每一行记录。我们通过
* 实现RowCallbackHandler接口中仅有的一个方法来完成上述功能。
* void processRow(java.sql.ResultSet rs)该方法将为ResultSet中的每条记录调用一次
* 这个方法只支持单对象的查询
*/
public Person getPerson(final Integer id){
String sql = "select id,first_Name,last_Name from person where id=?";
final Person person = new Person();//创建查询结果对象
final Object[] params = new Object[]{id};//创建查询参数
jdbcTemplate.query(sql,params,new RowCallbackHandler(){//处理查询结果
public void processRow(ResultSet rs)throws SQLException{
person.setId(new Integer(rs.getInt("id")));
person.setFirstName(rs.getString("first_name"));
person.setLastName(rs.getString("last_name"));
}
});
return person;//返回查询结果对象
}
/**//*
* 查询所有记录
* RowMapper接口对从一个查询结果中提取多个对象非常游泳。
*/
public List getAllPersons(){
String sql = "select id,first_name,last_name from person";
return jdbcTemplate.query(sql,new PersonRowMapper());
}
/**//*
* 查找基本类型
*/
public int getNumberOfPerson(){
return jdbcTemplate.queryForInt("select count(*) from person");
}
public String getLastNameForId(Integer id){
String sql = "select last_name from person where id=?";
return (String)jdbcTemplate.queryForObject(sql,new Object[]{id},String.class);
}
}
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
/**/ /*
* 为了让JdbcTemplate工作,它所需要的,只是一个DataSource实例。
*/
public class StudentDaoJdbc implements StudentDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**//*
* 先从SQL语句创建一个PreparedStatement,然后绑定参数。在幕后,JdbcTemplate
* 类创建了PreparedStatementCreator和PreparedStatementSetter.这些我们都
* 不用关心,我们只管提供SQL语句和参数。还可以提供类型支持。
*/
public int insertPerson(Person person){
String sql = "insert into person(id,firstName,lastName) values(?,?,?)";
Object[] params = new Object[]{person.getId(),person.getFirstName(),person.getLastName()};
return jdbcTemplate.update(sql,params);
}
public int insertPerson2(Person person){
String sql = "insert into person(id,firstName,lastName) values(?,?,?)";
Object[] params = new Object[]{person.getId(),person.getFirstName(),person.getLastName()};
int[] types = new int[]{Types.INTEGER,Types.VARBINARY,Types.VARBINARY};
return jdbcTemplate.update(sql, params, types);
}
/**//*
* 批量更新,我们讲使用BatchPreparedStatementSetter,这个接口的2个方法
* 1、getBatchSize()告诉JdbcTemplate类有多少个语句要创建,同时也决定了要调用多少次setValues()
* 2、setValues负责创建参数
* 所以你的JDBC驱动支持批量操作,这些更新讲被批量执行,是的数据访问更高效。
*/
public int[] updatePersons(final List persons){
String sql = "insert into person(id,firstName,lastName) values(?,?,?)";
BatchPreparedStatementSetter setter = null;
setter = new BatchPreparedStatementSetter(){
public int getBatchSize(){
return persons.size();
}
public void setValues(PreparedStatement ps,int index)throws SQLException{
Person person = (Person)persons.get(index);
ps.setInt(0,person.getId().intValue());
ps.setString(1,person.getFirstName());
ps.setString(2,person.getLastName());
}
};
return jdbcTemplate.batchUpdate(sql, setter);
}
/**//*
* 当查询数据库时,我们需要通过ResultSet取得结果,Spring认识到这一步是任何查询都需要的,所以它帮助
* 我们处理了这些。取而代之,我们只需要简单的告诉Spring要怎么处理ResultSet中的每一行记录。我们通过
* 实现RowCallbackHandler接口中仅有的一个方法来完成上述功能。
* void processRow(java.sql.ResultSet rs)该方法将为ResultSet中的每条记录调用一次
* 这个方法只支持单对象的查询
*/
public Person getPerson(final Integer id){
String sql = "select id,first_Name,last_Name from person where id=?";
final Person person = new Person();//创建查询结果对象
final Object[] params = new Object[]{id};//创建查询参数
jdbcTemplate.query(sql,params,new RowCallbackHandler(){//处理查询结果
public void processRow(ResultSet rs)throws SQLException{
person.setId(new Integer(rs.getInt("id")));
person.setFirstName(rs.getString("first_name"));
person.setLastName(rs.getString("last_name"));
}
});
return person;//返回查询结果对象
}
/**//*
* 查询所有记录
* RowMapper接口对从一个查询结果中提取多个对象非常游泳。
*/
public List getAllPersons(){
String sql = "select id,first_name,last_name from person";
return jdbcTemplate.query(sql,new PersonRowMapper());
}
/**//*
* 查找基本类型
*/
public int getNumberOfPerson(){
return jdbcTemplate.queryForInt("select count(*) from person");
}
public String getLastNameForId(Integer id){
String sql = "select last_name from person where id=?";
return (String)jdbcTemplate.queryForObject(sql,new Object[]{id},String.class);
}
}
package
com.testproject.spring.datasource;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class PersonRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int index) throws SQLException {
Person person = new Person();
person.setId(new Integer(rs.getInt("id")));
person.setFirstName(rs.getString("first_name"));
person.setLastName(rs.getString("last_name"));
return person;
}
}
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class PersonRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int index) throws SQLException {
Person person = new Person();
person.setId(new Integer(rs.getInt("id")));
person.setFirstName(rs.getString("first_name"));
person.setLastName(rs.getString("last_name"));
return person;
}
}