Spring数据访问对象(DAO)框架入门(1)
作者: 来源:it167 点击: 日期:2007-01-28 |
|
|
最后,如果数据库不支持自动类型转换,需要如下所示,对JUnit测试类中的initSalaryMap()方法稍做修改。
private void initSalaryMap() {
salaryMap = new HashMap();
salaryMap.put("MIN_SALARY",new Double(1));
salaryMap.put("MAX_SALARY",new Double(50));
}
|
至此,已经说明为了解决传统DAO设计中存在的问题,如何封装和概括JdbcTemplate类中JDBC代码的静态部分。现在了解一下有关变量的问题,如设置绑定变量、结果集遍历等。虽然Spring DAO已经拥有这些问题的一般化解决方案,但在某些基于SQL的情况下,可能仍需要设置绑定变量。
在尝试向Spring DAO转换的过程中,介绍了由于业务服务及其客户机之间的约定遭到破坏而导致的隐蔽运行时错误。这个错误的来源可以追溯到原始的DAO.dbcTemplate.queryForList()方法不再返回EmployeeTO实例列表。而是返回一个map表(每个map是结果集的一行)。
如您目前所知,JdbcTemplate基于模板方法设计模式,该模式利用JDBC API定义SQL执行工作流。必须改变这个工作流以修复被破坏的约定。第一个选择是在子类中更改或扩展工作流。您可以遍历JdbcTemplate.queryForList()返回的列表,用EmployeeTO实例替换map对象。然而,这会导致我们一直竭力避免的静态代码与动态代码的混合。第二个选择是将代码插入JdbcTemplate提供的各种工作流修改钩子(hook)。明智的做法是在一个不同的类中封装传输对象填充代码,然后通过钩子链接它。填充逻辑的任何修改将不会改变DAO.
编写一个类,使其实现在Spring框架特定的接口中定义的方法,就可以实现第二个选择。这些方法称为回调函数,通过JdbcTemplate向框架注册。当发生相应的事件(例如,遍历结果集并填充独立于框架的传输对象)时,框架将调用这些方法。
第一步:传输对象
下面是您可能感兴趣的传输对象。注意,以下所示的传输对象是固定的:
package com.bea.dev2dev.to; public final class EmployeeTO implements Serializable{ private int empNo;
private String empName;
private double salary; /** Creates a new instance of EmployeeTO */
public EmployeeTO(int empNo,String empName,double salary) {
this.empNo = empNo;
this.empName = empName;
this.salary = salary;
}
public String getEmpName() {
return this.empName;
}
public int getEmpNo() {
return this.empNo;
}
public double getSalary() {
return this.salary;
}
public boolean equals(EmployeeTO empTO){
return empTO.empNo == this.empNo;
}
}
|
第二步:实现回调接口
实现RowMapper接口,填充来自结果集的传输对象。下面是一个例子:
package com.bea.dev2dev.dao.mapper; import com.bea.dev2dev.to.EmployeeTO;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper; public class EmployeeTOMapper implements RowMapper{ public Object mapRow(ResultSet rs, int rowNum)
throws SQLException{
int empNo = rs.getInt(1);
String empName = rs.getString(2);
double salary = rs.getDouble(3);
EmployeeTO empTo = new EmployeeTO(empNo,empName,salary);
return empTo;
}
}
|
注意实现类不应该对提供的ResultSet对象调用next()方法。这由框架负责,该类只要从结果集的当前行提取值就行。回调实现抛出的任何SQLException也由Spring框架处理。
第三步:插入回调接口
执行SQL查询时,JdbcTemplate利用默认的RowMapper实现产生map列表。现在需要注册自定义回调实现来修改JdbcTemplate的这一行为。注意现在用的是NamedParameterJdbcTemplate的query()方法,而不是queryForList()方法:
public class EmployeeDAOImpl extends NamedParameterJdbcDaoSupport
implements IEmployeeDAO{ public List findBySalaryRange(Map salaryMap){ NamedParameterJdbcTemplate daoTmplt =
getNamedParameterJdbcTemplate();
return daoTmplt.query(IEmployeeDAO.FIND_BY_SAL_RNG, salaryMap,
new EmployeeTOMapper());
}
}
|
Spring DAO框架对执行查询后返回的结果进行遍历。它在遍历的每一步调用EmployeeTOMapper类实现的mapRow()方法,使用EmployeeTO传输对象填充最终结果的每一行。
第四步:修改后的JUnit类
现在要根据返回的传输对象测试这些结果。为此要对测试方法进行修改。
public class EmployeeBusinessServiceImplTest extends TestCase { private IEmployeeBusinessService empBusiness;
private Map salaryMap;
List expResult; // all methods not shown in the listing remain the
// same as in the previous example
private void initExpectedResult() {
expResult = new ArrayList();
EmployeeTO to = new EmployeeTO(2,"John",46.11);
expResult.add(to);
} /**
* Test of getEmployeesWithinSalaryRange method, of
* class com.bea.dev2dev.business.
* EmployeeBusinessServiceImpl
*/
public void testGetEmployeesWithinSalaryRange() {
List result = empBusiness.
getEmployeesWithinSalaryRange(salaryMap);
assertEquals(expResult, result);
} public void assertEquals(List expResult, List result){
EmployeeTO expTO = (EmployeeTO) expResult.get(0);
EmployeeTO actualTO = (EmployeeTO) result.get(0);
if(!expTO.equals(actualTO)){
throw new RuntimeException("** Test Failed **");
}
}
}
|
优势
Spring JDBC框架的优点很清楚。我们获益很多,并将DAO方法简化到只有几行代码。代码不再脆弱,这要感谢该框架对命名的参数绑定变量的“开箱即用”支持,以及在映射程序中将传输对象填充逻辑分离。
Spring JDBC的优点应该促使您向这一框架移植现有的代码。希望本文在这一方面能有所帮助。它会帮助您获得一些重构工具和知识。例如,如果您没有采用P2I Extract Interface,那么可以使用重构,从现有的DAO实现类创建接口。除此之外,查看本文的参考资料可以得到更多指导。
共5页: 上一页 [1] [2] [3] [4] 5 下一页
|