`
pharaohsprince
  • 浏览: 289508 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

SPRING数据访问对象(DAO)框架入门

阅读更多


 

摘要

  J2EE应用程序中的业务组件通常使用JDBC API访问和更改关系数据库中的持久数据。这经常导致持久性代码与业务逻辑发生混合,这是一种不好的习惯。数据访问对象(DAO)设计模式通过把持久性逻辑分成若干数据访问类来解决这一问题。

  本文是一篇关于DAO设计模式的入门文章,突出讲述了它的优点和不足之处。另外,本文还介绍了Spring 2.0 JDBC/DAO框架并示范了它如何妥善地解决传统DAO设计中的缺陷。

传统的DAO设计

  数据访问对象(DAO)是一个集成层设计模式,如Core J2EE Design Pattern 图书所归纳。它将持久性存储访问和操作代码封装到一个单独的层中。本文的上下文中所提到的持久存储器是一个RDBMS。

  这一模式在业务逻辑层和持久存储层之间引入了一个抽象层,如图1所示。业务对象通过数据访问对象来访问RDBMS(数据源)。抽象层改善了应用程序代码并引入了灵活性。理论上,当数据源改变时,比如更换数据库供应商或是数据库的类型时,仅需改变数据访问对象,从而把对业务对象的影响降到最低。

SPRING数据访问对象(DAO)框架入门图-1

  图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}

 

  上面的清单说明了DAO方法的一些要点:

  • 它们封装了所有与JDBC API的交互。如果使用像Kodo或者Hibernate的O/R映射方案,则DAO类可以将这些产品的私有API打包。
  • 它们将检索到的数据打包到一个与JDBC API无关的传输对象中,然后将其返回给业务层作进一步处理。
  • 它们实质上是无状态的。唯一的目的是访问并更改业务对象的持久数据。
  • 在这个过程中,它们像SQLException一样捕获任何底层JDBC API或数据库报告的错误(例如,数据库不可用、错误的SQL句法)。DAO对象再次使用一个与JDBC无关的自定义运行时异常类DBException,通知业务对象这些错误。
  • 它们像Connection和PreparedStatement对象那样,将数据库资源释放回池中,并在使用完ResultSet游标之后,将其所占用的内存释放。

  因此,DAO层将底层的数据访问API抽象化,为业务层提供了一致的数据访问API。

构建DAO工厂

  DAO工厂是典型的工厂设计模式实现,用于为业务对象创建和提供具体的DAO实现。业务对象使用DAO接口,而不用了解实现类的具体情况。DAO工厂带来的依赖反转(dependency inversion)提供了极大的灵活性。只要DAO接口建立的约定未改变,那么很容易改变DAO实现(例如,从straight JDBC实现到基于Kodo的O/R映射),同时又不影响客户的业务对象:

 

public class DAOFactory ...{  private static DAOFactory daoFac;  static...{
    daoFac 
= new DAOFactory();  }
  private DAOFactory()...{}
  
public DAOFactory getInstance()...{    return daoFac;  }
  
public IEmployeeDAO getEmployeeDAO()...{    return new EmployeeDAOImpl();  }}

 

与业务组件的协作

  现在该了解DAO怎样适应更复杂的情形。如前几节所述,DAO与业务层组件协作获取和更改持久业务数据。下面的清单展示了业务服务组件及其与DAO层的交互:

 

public class EmployeeBusinessServiceImpl implements 
                                       IEmployeeBusinessService 
...{
  
public List getEmployeesWithinSalaryRange(Map salaryMap)...{
    IEmployeeDAO empDAO 
= DAOFactory.getInstance()
                                    .getEmployeeDAO();
    List empList 
= empDAO.findBySalaryRange(salaryMap);    return empList;  }
}

 

  交互过程十分简洁,完全不依赖于任何持久性接口(包括JDBC)。

问题

  DAO设计模式也有缺点:

  • 代码重复:从EmployeeDAOImpl清单可以清楚地看到,对于基于JDBC的传统数据库访问,代码重复(如上面的粗体字所示)是一个主要的问题。一遍又一遍地写着同样的代码,明显违背了基本的面向对象设计的代码重用原则。它将对项目成本、时间安排和工作产生明显的副面影响。
  • 耦合:DAO代码与JDBC接口和核心collection耦合得非常紧密。从每个DAO类的导入声明的数量可以明显地看出这种耦合。
  • 资源耗损:依据EmployeeDAOImpl类的设计,所有DAO方法必须释放对所获得的连接、声明、结果集等数据库资源的控制。这是危险的主张,因为一个编程新手可能很容易漏掉那些约束。结果造成资源耗尽,导致系统停机。
  • 错误处理:JDBC驱动程序通过抛出SQLException来报告所有的错误情况。SQLException是检查到的异常,所以开发人员被迫去处理它,即使不可能从这类导致代码混乱的大多数异常中恢复过来。而且,从SQLException对象获得的错误代码和消息特定于数据库厂商,所以不可能写出可移植的DAO错误发送代码。
  • 脆弱的代码:在基于JDBC的DAO中,两个常用的任务是设置声明对象的绑定变量和使用结果集检索数据。如果SQL where子句中的列数目或者位置更改了,就不得不对代码执行更改、测试、重新部署这个严格的循环过程。

  让我们看看如何能够减少这些问题并保留DAO的大多数优点。

进入Spring DAO

  先识别代码中发生变化的部分,然后将这一部分代码分离出来或者封装起来,就能解决以上所列出的问题。Spring的设计者们已经完全做到了这一点,他们发布了一个超级简洁、健壮的、高度可伸缩的JDBC框架。固定部分(像检索连接、准备声明对象、执行查询和释放数据库资源)已经被一次性地写好,所以该框架的一部分内容有助于消除在传统的基于JDBC的DAO中出现的缺点。

  图2显示的是Spring JDBC框架的主要组成部分。业务服务对象通过适当的接口继续使用DAO实现类。JdbcDaoSupport是JDBC数据访问对象的超类。它与特定的数据源相关联。Spring Inversion of Control (IOC)容器或BeanFactory负责获得相应数据源的配置详细信息,并将其与JdbcDaoSupport相关联。这个类最重要的功能就是使子类可以使用JdbcTemplate对象。

SPRING数据访问对象(DAO)框架入门图-2

  图2. Spring JDBC框架的主要组件

  JdbcTemplate是Spring JDBC框架中最重要的类。引用文献中的话:“它简化了JDBC的使用,有助于避免常见的错误。它执行核心JDBC工作流,保留应用代码以提供SQL和提取结果。”这个类通过执行下面的样板任务来帮助分离JDBC DAO代码的静态部分:

  • 从数据源检索连接。
  • 准备合适的声明对象。
  • 执行SQL CRUD操作。
  • 遍历结果集,然后将结果填入标准的collection对象。
  • 处理SQLException异常并将其转换成更加特定于错误的异常层次结构。

利用Spring DAO重新编写

  既然已基本理解了Spring JDBC框架,现在要重新编写已有的代码。下面将逐步讲述如何解决前几节中提到的问题。

第一步:修改DAO实现类- 现在从JdbcDaoSupport扩展出EmployeeDAOImpl以获得JdbcTemplate。

 

import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.core.JdbcTemplate;
public class EmployeeDAOImpl extends JdbcDaoSupport 
                                     
implements IEmployeeDAO...{
  
public List findBySalaryRange(Map salaryMap)...{
    Double dblParams [] 
= ...{Double.valueOf((String)
            salaryMap.get(
"MIN_SALARY"))              ,Double.valueOf((String)
            salaryMap.get(
"MAX_SALARY"))            }
;
    
//The getJdbcTemplate method of JdbcDaoSupport returns an
    
//instance of JdbcTemplate initialized with a datasource by the
    
//Spring Bean Factory    JdbcTemplate daoTmplt = this.getJdbcTemplate();
    return daoTmplt.queryForList(FIND_BY_SAL_RNG,dblParams);   }
}


  在上面的清单中,传入参数映射中的值存储在双字节数组中,顺序与SQL字符串中的位置参数相同。queryForList()方法以包含Map(用列名作为键,一项对应一列)的List(一项对应一行)的方式返回查询结果。稍后我会说明如何返回传输对象列表。

  从简化的代码可以明显看出,JdbcTemplate鼓励重用,这大大削减了DAO实现中的代码。JDBC和collection包之间的紧密耦合已经消除。由于JdbcTemplate方法可确保在使用数据库资源后将其按正确的次序释放,所以JDBC的资源耗损不再是一个问题。

  另外,使用Spring DAO时,不必处理异常。JdbcTemplate类会处理SQLException,并根据SQL错误代码或错误状态将其转换成特定于Spring异常的层次结构。例如,试图向主键列插入重复值时,将引发DataIntegrityViolationException。然而,如果无法从这一错误中恢复,就无需处理该异常。因为Spring DAO的根异常类DataAccessException是运行时异常类,所以可以这样做。值得注意的是Spring DAO异常独立于数据访问实现。如果实现是由O/R映射解决方案提供,就会抛出同样的异常。

第二步:修改业务服务- 现在业务服务实现了一个新方法setDao(),Spring容器使用该方法传递DAO实现类的引用。该过程称为“设置方法注入(setter injection)”,通过第三步中的配置文件告知Spring容器该过程。注意,不再需要使用DAOFactory,因为Spring BeanFactory提供了这项功能:

 

public class EmployeeBusinessServiceImplimplements IEmployeeBusinessService ...{

  IEmployeeDAO empDAO;

  
public List getEmployeesWithinSalaryRange(Map salaryMap)...{

    List empList 
= empDAO.findBySalaryRange(salaryMap);
    
return empList;
  }
 
  
public void setDao(IEmployeeDAO empDAO)...{
    
分享到:
评论

相关推荐

    Struts+Spring+Hibernate快速入门

    本文是开发基于spring的web应用的入门文章,前端采用Struts MVC框架,中间层采用spring,后台采用Hibernate。  本文包含以下内容:  •配置Hibernate和事务  •装载Spring的applicationContext.xml文件  •...

    开源框架 Spring Gossip

    Spring MVC 入门 从一个最简单的 Spring Web 应用程式,来看看 Spring MVC 框架的架构与 API 组成元素。 第一个 Spring MVC 程式 WebApplicationContext Handler Mapping Handler ...

    SSM框架教程Spring+SpringMVC+MyBatis全覆盖_Java热门框架视频教程

    1、Spring简介及快速入门 2、Spring配置文件及其相应API 3、Spring注解开发 4、Spring web环境及其Junit的集成 5、Spring JDBCTemplate的基本使用 6、Spring AOP的介绍及其配置使用 7、Spring的声明式事务控制 8、...

    Spring Framework 5 中文文档

    15.使用JDBC实现数据访问 16. ORM和数据访问 17. 使用 O/X(Object/XML)映射器对XML进行编组 19. 视图技术 20. CORS支持 21. 与其他Web框架集成 22. WebSocket支持 24. 使用Spring提供远程和WEB服务 25. 整合EJB 26. ...

    spring data jpa入门实例

    spring Data家族给我们提供了一个现成的dao层框架,这里面有不同的项目,如Spring Data JPA, Spring Data Neo4j and Spring Data MongoDB,他们的共同特点是他们给我们提供了框架代码,不再需要我们自己去实现了。

    Spring.3.x企业应用开发实战(完整版).part2

    1.5.5 数据访问层新增OXM功能 1.5.6 Web层的增强 1.5.7 其他 1.6 Spring对Java版本的要求 1.7 如何获取Spring 1.8 小结 第2章 快速入门 2.1 实例功能概述 2.1.1 比Hello World更适用的实例 2.1.2 实例功能简介 2.2 ...

    完整版 Java开发实训课程系列-MyBatis框架技术 01.Mybatis框架入门(共23页).pptx

    完整版 Java开发实训课程系列-MyBatis框架技术 01.Mybatis框架入门(共23页).pptx 完整版 Java开发实训课程系列-MyBatis框架技术 02.MyBatis核心配置与DAO开发(共34页).pptx 完整版 Java开发实训课程系列-MyBatis...

    Spring 5 英文文档全套.7z

    模拟对象,TestContext框架,Spring MVC测试,WebTestClient。 资料存取 事务,DAO支持,JDBC,O / R映射,XML编组。 Web Servlet Spring MVC,WebSocket,SockJS,STOMP消息传递。 网络反应 Spring WebFlux,...

    Spring3.x企业应用开发实战(完整版) part1

    1.5.5 数据访问层新增OXM功能 1.5.6 Web层的增强 1.5.7 其他 1.6 Spring对Java版本的要求 1.7 如何获取Spring 1.8 小结 第2章 快速入门 2.1 实例功能概述 2.1.1 比Hello World更适用的实例 2.1.2 实例功能简介 2.2 ...

    J2EE三大框架_笔记_a

    46-Spring入门 47Spring_IOC(下)笔记 47-Spring_IOC-v(上)笔记 48Spring_AOP笔记 49-Spring_JDBC模板笔记 50-Spring_Struts、Hibernate支持笔记 51-52使用Struts + Spring + Hibernate完成用户登陆笔记 53使用...

    《精通Spring2.X企业应用开发详解》随书源码1-15章

    第三部分涵盖了在Spring中使用各种数据访问技术的内容;第四部分讲解业务层各种技术的知识;第五部分是展现层技术的知识;第六部分讲解了如何测试Spring应用和Spring各种工具类的知识。 全书深刻揭示了Spring的技术...

    Spring 快速入门教程

    学习用struts MVC框架作前端,Spring做中间层,Hibernate作后端来开发一个 简单的Spring应用程序。在第4章将使用Spring MVC框架对它进行重构。 本章包含以下内容: 编写功能性测试。 配置Hibernate和Transaction。 ...

    Spring+SpringMVC+MyBatis入门必备

    Spring+SpringMVC+mybatist三大框架整合项目,java代码分为 dao,service,controller三层,支持注 解,事务。数据库默认MySQL,配置文件为src下的config资源包中的 db.properties,以KEY VALUE形式保存数据库连接属性...

    J2EE框架_笔记_c

    46-Spring入门 47Spring_IOC(下)笔记 47-Spring_IOC-v(上)笔记 48Spring_AOP笔记 49-Spring_JDBC模板笔记 50-Spring_Struts、Hibernate支持笔记 51-52使用Struts + Spring + Hibernate完成用户登陆笔记 53使用...

    J2EE框架_笔记_b

    46-Spring入门 47Spring_IOC(下)笔记 47-Spring_IOC-v(上)笔记 48Spring_AOP笔记 49-Spring_JDBC模板笔记 50-Spring_Struts、Hibernate支持笔记 51-52使用Struts + Spring + Hibernate完成用户登陆笔记 53使用...

    Spring攻略(第二版 中文高清版).part1

    本书共分为两卷。 第1章 Spring简介 1 1.1 实例化Spring IoC容器 1 1.1.1 问题 1 1.1.2 解决方案 1 1.1.3 工作原理 3 1.2 配置Spring IoC容器中的Bean 4 1.2.1 问题 4 ...第15章 数据访问 570 ...

    完整版 Java开发实训课程系列-MyBatis框架技术 02.MyBatis核心配置与DAO开发(共34页).pptx

    完整版 Java开发实训课程系列-MyBatis框架技术 01.Mybatis框架入门(共23页).pptx 完整版 Java开发实训课程系列-MyBatis框架技术 02.MyBatis核心配置与DAO开发(共34页).pptx 完整版 Java开发实训课程系列-MyBatis...

    完整版 Java开发实训课程系列-MyBatis框架技术 04.MyBatis与Spring整合开发(共21页).pptx

    完整版 Java开发实训课程系列-MyBatis框架技术 01.Mybatis框架入门(共23页).pptx 完整版 Java开发实训课程系列-MyBatis框架技术 02.MyBatis核心配置与DAO开发(共34页).pptx 完整版 Java开发实训课程系列-MyBatis...

    《精通Spring2.X企业应用开发详解》16-19章

    第三部分涵盖了在Spring中使用各种数据访问技术的内容;第四部分讲解业务层各种技术的知识;第五部分是展现层技术的知识;第六部分讲解了如何测试Spring应用和Spring各种工具类的知识。 全书深刻揭示了Spring的技术...

Global site tag (gtag.js) - Google Analytics