摘要
J2EE应用程序中的业务组件通常使用JDBC API访问和更改关系数据库中的持久数据。这经常导致持久性代码与业务逻辑发生混合,这是一种不好的习惯。数据访问对象(DAO)设计模式通过把持久性逻辑分成若干数据访问类来解决这一问题。
本文是一篇关于DAO设计模式的入门文章,突出讲述了它的优点和不足之处。另外,本文还介绍了Spring 2.0 JDBC/DAO框架并示范了它如何妥善地解决传统DAO设计中的缺陷。
传统的DAO设计
数据访问对象(DAO)是一个集成层设计模式,如Core J2EE Design Pattern 图书所归纳。它将持久性存储访问和操作代码封装到一个单独的层中。本文的上下文中所提到的持久存储器是一个RDBMS.
这一模式在业务逻辑层和持久存储层之间引入了一个抽象层,如图1所示。业务对象通过数据访问对象来访问RDBMS(数据源)。抽象层改善了应用程序代码并引入了灵活性。理论上,当数据源改变时,比如更换数据库供应商或是数据库的类型时,仅需改变数据访问对象,从而把对业务对象的影响降到最低。
图1. 应用程序结构,包括DAO之前和之后的部分
讲解了DAO设计模式的基础知识,下面将编写一些代码。下面的例子来自于一个公司域模型。简而言之,这家公司有几位员工工作在不同的部门,如销售部、市场部以及人力资源部。为了简单起见,我们将集中讨论一个称作“雇员”的实体。
针对接口编程
DAO设计模式带来的灵活性首先要归功于一个对象设计的最佳实践:针对接口编程(P2I)。这一原则规定实体必须实现一个供调用程序而不是实体自身使用的接口。因此,可以轻松替换成不同的实现而对客户端代码只产生很小的影响。
我们将据此使用findBySalaryRange()行为定义Employee DAO接口,IEmployeeDAO.业务组件将通过这个接口与DAO交互:
import java.util.Map; public interface IEmployeeDAO { //SQL String that will be executed public String FIND_BY_SAL_RNG = "SELECT EMP_NO, EMP_NAME, " + "SALARY FROM EMP WHERE SALARY >= ? AND SALARY <= ?";
//Returns the list of employees who fall into the given salary //range. The input parameter is the immutable map object //obtained from the HttpServletRequest. This is an early //refactoring based on "Introduce Parameter Object"
public List findBySalaryRange(Map salaryMap); }
|
提供DAO实现类
接口已经定义,现在必须提供Employee DAO的具体实现,EmployeeDAOImpl:
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.List; import java.util.ArrayList; import java.util.Map; import com.bea.dev2dev.to.EmployeeTO;
public class EmployeeDAOImpl implements IEmployeeDAO{
public List findBySalaryRange(Map salaryMap) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; List empList = new ArrayList(); //Transfer Object for inter-tier data transfer EmployeeTO tempEmpTO = null; try{ //DBUtil - helper classes that retrieve connection from pool conn = DBUtil.getConnection(); pstmt = conn.prepareStatement(FIND_BY_SAL_RNG); pstmt.setDouble(1, Double.valueOf( (String) salaryMap.get("MIN_SALARY") ); pstmt.setDouble(2, Double.valueOf( (String) salaryMap.get("MIN_SALARY") ); rs = pstmt.executeQuery(); int tmpEmpNo = 0; String tmpEmpName = ""; double tmpSalary = 0.0D; while (rs.next()){ tmpEmpNo = rs.getInt("EMP_NO"); tmpEmpName = rs.getString("EMP_NAME"); tmpSalary = rs.getDouble("SALARY"); tempEmpTO = new EmployeeTO(tmpEmpNo, tmpEmpName, tmpSalary); empList.add(tempEmpTO); }//end while }//end try catch (SQLException sqle){ throw new DBException(sqle); }//end catch finally{ try{ if (rs != null){ rs.close(); } } catch (SQLException sqle){ throw new DBException(sqle); } try{ if (pstmt != null){ pstmt.close(); } } catch (SQLException sqle){ throw new DBException(sqle); } try{ if (conn != null){ conn.close(); } } catch (SQLException sqle){ throw new DBException(sqle); } }//end of finally block return empList; }//end method findBySalaryRange }
|
[1] [2] [3] [4] [5] [6] 下一页