DAO设计模式详细--实例开发

DAO设计模式详细–实例开发

Data Access Object,数据访问对象

javabean是把视图和业务进行分离,dao是把数据库的操作和业务逻辑进行分离.

主要的功能是用于进行数据操作的,在程序的标准开发框架中属于数据层的操作。

网络博客学习

20141207130012401
  1. 我们需要理解程序分层的思想
  2. DAO设计模式的组成以及各部分的开发

1.0 程序的分层思想

分层的思想:

我们可以这么理解,实际上分层概念可以应用到任何环境上,例如:公司里可以按照职位分层,每一层都是完全独立的,而且可以和其它层进行完整的交互

​ 我们可以以人类交谈为例子做一个简单分层

  1. 两个人进行交谈的时候,所有的信息都存储在大脑里面,大脑是作为信息存储的单位存在,
  2. 我们需要依赖语言或者行为模式组合数据进行交流
  3. 为了友好交流,我们还需要一些辅助性的外表交流

如果要对程序进行划分, 那么最常见的划分方式:

显示层+控制层+业务层+数据层+数据库

image 20200813201346403 image 20200813225631109

在一个项目中,实现的关键是业务层,前台显示同样重要,因为只有一个好的页面才能够让用户印象深刻.我们在DAO设计中主要观察业务层和数据层的开发,到了javaWeb后,才开始实习显示层和控制层的开发

项目的后台建立有着重要地位,不同层之间最为重要的联结组成就是接口,所有在整个项目开发之中,后台代码就一定要有两个组成接口

  • 业务接口:以后给控制层使用
  • 数据层接口:以后给业务层使用

我们聊了这么多,到底什么是业务层,和数据层那?

  • 数据层(数据访问层,Database Access )指的是执行数据库的具体操作,而现在的开发之中,大多数都是针对与数据库的开发,所以在数据库中的主要任务是负责完成数据的CRUD.肯定使用数据库Preparedstatement接口完成
  • 业务层(业务对象,Bussiness object,BO) 又或者将其称为Service,服务层,业务层的主要任务是根据业务需求进行数据层的操作,一个业务层要包含多个数据层的操作
image 20200813224215486

一个业务层需要多个数据层的操作共同完成

我们发现数据层里,完成的都是一个一个的原子性的操作

大的业务可能会被细分为小的业务

image 20200813225801667

2.0案例分析

现在要求使用emp表(empno,ename,job,hiredate,sal,comm)实现以下操作

  1. [业务层]增加雇员信息,但是需要保证新添加的雇员编号不会重复
    1. [数据层]判断我们要增加的雇员编号是否存在
    2. [数据层]如果雇员编号不存在,则进行数据的保存操作
  2. [业务层]实现雇员数据的修改操作
    1. [数据层]执行数据修改操作
  3. [业务层]实现多个雇员数据的删除操作
    1. [数据层]执行数据的限定删除
  4. [业务层]可以根据雇员编号查找到一个雇员的信息
    1. [数据层]根据雇员编号查询指定的雇员信息
  5. [业务层]可以查询雇员所有的信息
    1. [数据层]查询全部雇员数据
  6. [业务层]可以实现数据的分页显示,同时又可以返回所有的雇员数量
    1. [数据层]雇员信息的分页查询
    2. [数据层]视图count函数查询雇员数量
image 20200813232311652

我们可以得出结论:用户提出的所有需求都应该划分为业务层,因为它指的是功能,而开发人员必须根据业务机进行数据层的设计

3.0 项目的准备

我们的项目只需要一行表即可

drop table if exists emp;

/*==============================================================*/
/* Table: emp                                                   */
/*==============================================================*/
create table emp
(
   empno                int not null,
   ename                varchar(255),
   job                  varchar(255),
   hiredate             date,
   sal                  double,
   comm                 double,
   primary key (empno)
);

image 20200814152003469

我们首先进行项目的创建和数据库的配置

项目名称DAOProject

所有项目的父包叫com.rango,子包根据具体功能进行细分

3.1数据库连接类

我们单独定义一个DataConnection类,这个类主要负责数据库连接对象,负责数据库的连接操作

我们将它保存在dbc子包之中,定义数据库连接类

package com.rango.dbc;

import java.sql.*;

/**
* @program: DAO设计模式学习
* @description: 整个项目的数据库连接类,项目的准备工作
* @author: JiaYadong
* @create: 
**/
public class DatabaseConnection {
       /* 工具类中的方法都是私有的
       *因为工具类当中的方法都是静态的,不需要太new对象,直接采用类名调用
       * */

       private DatabaseConnection(){

       }

//        静态代码在类加载时执行,并且只执行一次

   static {
           try{
               Class.forName("com.mysql.jdbc.Driver");
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           }
   }
//    获取连接对象

   /**
    * 
    * @return 连接对象
    * @throws SQLException 方法跑出异常,主方法里接收异常
    */
   private static Connection getConnection() throws SQLException {
       return DriverManager.getConnection("jdbc:mysql://localhost:3306/test_db?characterEncoding=utf8",
       "root", "123456");
   }
   
   //关闭数据库操作,我重写了好几个数据操作对象

   private static void close(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet){
       if (resultSet != null) {
           try {
               resultSet.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if (preparedStatement != null) {
           try {
               preparedStatement.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }

       if (connection != null) {
           try {
               connection.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
   }

   
   
}

3.2 开发value-object

程序分层后实际上都是指面向对象的分层,而不同层之间(这些层除了数据层要操作的是sql语句之外,其他层操作的数据都应该是对象)是需要数据传递的,那么就应该有一个负责传输的数据对象,而这个对象需要和一条数据进行完整的映射,我们想到了简单java类(po,pojo,vo,to)

数据层和业务层都是通过简单java类进行交互,在实际的工作之中,针对简单java类的开发给出如下的要求,

  • 考虑到日后程序可能会出现的分布式应用问题,所以简单java类对必须实现java.io.serializable
  • 简单java类的名称必须与表名称保持一致
    • 有可能采用这个样的名字(驼峰命名法),student_info,StudentInfo
  • 类中的属性不允许使用基本数据类型,都必须使用基本数据类型的包装类
    • 基本数据类型的默认值有可能是0,而如果是包装类默认值就是null
  • 类中可以定义有多个构造方法,但是必须保留一个无参的构造方法
  • 类中的属性必须是private,封装后的属性必须要有setter,getter

我们将所有简单类保存在vo包中,

public class Emp implements Serializable {
    private Integer empno;
    private String  ename;
    private String job;
    private Date hiredate;
    private Double sal;
    private Double comm;
​`````getter和setter省略
}

4.0 开发数据层

数据层的主要操作是使用SQL语句与数据库进行交互,其功能如下

image 20200814074448817

数据层最终是交给业务层调用的,所有业务层必须知道数据层的执行标准,即:业务层需要明确的知道数据层的执行标准 ,但是不必知道具体实现方法

4.1 开发数据层操作标准

不同层直接如果要进行访问,那么必须要提供有接口,以定义操作标准,对于数据层也是一样的,数据层也是交给业务层处理,所以我们要知道数据层操作标准

对于数据层的接口给出如下的开发要求

  • 数据层既然是进行数据操作的,那么就将其保存到dao包下面

  • 既然不同数据表对于不用数据层操作开发,我们可以用一下命名

    • emp表,我们的数据层的接口就应该定义为IEmpDAO
  • 对于数据层的开发严格来讲就只有两类功能

  • 数据更新:建议它的操作方法以doXxx()的形式命名,例如doCreate,doUpdate,doRemove

  • 查询操作:查询操作分为两类

    • **数据查询:**对于查询分为两种形式以findByXxx()为主,如findAll(),findById(),findByJob()
    • **统计查询:**以getXxx()或者getByXxx()为主,如getAllCount,getByJobcount()
image 20200814135429948

4.2 数据层实现类

实现类中比较难的几个点,

模糊分页查询,早oracle和mysql中分页查询不同

为了方便阐述,下面统一使用student表作为查询的表;colName表示student表中的某个字段名字。  
1、mysql

  select * from student (order by colName) limit m, n;

    参数解释  m:表示要查询记录的上一行的行号,比如要从第1条记录开始查则m取0;

           n:表示希望从m+1开始查询多少条记录;
    select*from emp (order by )
 2、oracle

  select * from (select t.*,rownum rn from (select * from student) t where rownum<=m) where rn>=n;

  参数解释  rownum:是oracle系统为查询返回的行顺序分配的编号
				m:查询的最大行号;

           n:查询的最小行号;

         这样查询的结果行数为:m-n+1
         

插入知识[jdbc中如何实现动态分页]

二、jdbc中如何实现动态分页

1、四个重要参数

pageNow  当前的页码

pageCount 总页数

pageSize  每页中显示多少条记录

rowCount  表中记录的总行数

2、根据rowCount和pageSize计算pageCount的小算法

①  if(rowCount % pageSize == 0) {

pageCount = rowCount / pageSize;

} else {

pageCount = rowCount / pageSize + 1;

}

②  pageCount = rowCount % pageSize == 0 ? rowCount / pageSize : rowCount / pageSize + 1;

③  pageCount = (rowCount - 1) / pageSize + 1;

原理是一样的,只是给出了三种形式,个人比较喜欢③。

3、将pageSize和pageNow用在jdbc的sql语句中查询当前页的记录

⑴mysql

select * from student (order by colName) limit (pageNow-1)*pageSize, pageSize;

⑵oracel

select * from (select t.,rownum rn from (select * from student) t where rownum<=pageNowpageSize) where rn>=(pageNow-1)*pageSize+1;

⑶sql server

select top pageSize * from student where stuid>( select max(stuid) from ( select top (pageNow-1)*pageSize stuid from student order by stuid ) as t ) order by stuid;

sql server分页查询语句中,这条语句的效率较高,其他的几种查询形式这里就不讨论了。

4.3定义DAO工厂类

用户在开发过程中不用知道子类的具体实现方法,只需要依靠接口取得数据层对象,数据库连接对象,就行

public class DAOFactory {
    public IEmpDAO getIEmpDAOInstance(Connection connection){
        return new EmpDAOImpl(connection);
    }
}

5.0 开发业务层

业务层的主要功能是调用数据层操作,而数据层之间的数据传输都是利用简单java类完成的

image 20200814201911601

5.1 开发层标准–IEmpService

业务层以后也是需要留给其它层进行调用的,所以业务层定义时也需要首先定义出操作标准:任然是老三样 接口Interface—>实现类—>工厂类

对于业务层,接口命名要求为表名称+Service,如IEmpService,表示操作Emp表的业务

5.2定义业务层标准的实现类

业务层实现类的核心功能

  • 负责控制数据库的打开和关闭,当存在了业务层对象之后其目的就是为了操作数据库,即:业务层对象实例化之后就必须准备好数据库连接
  • 根据DAOFactory调用getIEmpDAOInstance方法之后取得IEmpDAO接口对象,业务层的实现类保存在

 不同层直接的访问依靠的就是工厂类和接口进行操作

5.3定义业务层工厂类ServiceFactory

业务层最终依然需要被其他的层所使用,所以需要为其定义工作类

如果要取得IEmpService接口对象,一定需要使用工厂类避免耦合问题 

从开发来讲,业务层分为两种:

  • 前台逻辑:可以将其保存在service.front包中,工厂类,:serviceFrontFactory
  • 后台逻辑:可以将其保存在service.back包中,工厂类:serviceBackFactory

在实际的编写之中,子类永远都是不可见的,同时在整个操作里面,控制层看不到任何的JDBC代码

6.0 测试操作

程序完成之后,我们需要编写测试程序,有两种方法完成测试程序

  1. 方法一:可以直接编写主方法,自己根据它的返回值结果进行判断是否成功
  2. 方法二:利用Junit完成,这样的做法标准,而且也方便日后调试
package com.rango.Test;

import com.rango.factory.ServiceFactory;
import com.rango.vo.Emp;

import java.util.Date;

/**
 * @program: DAO设计模式学习
 * @description: 测试插入类
 * @author: JiaYadong
 * @create: 2020-08-15 15:12
 **/
public class TestEmpInsert {
    public static void main(String[] args){
        Emp vo=new Emp();
        vo.setEmpno(1234);
        vo.setEname("陈冠希");
        vo.setJob("摄影师");
        vo.setHiredate(new Date());
        vo.setSal(1500.0);
        vo.setComm(200.0);
//        数据保存之前要检查数据库里是否存在这些值
        try {
            System.out.println(ServiceFactory.getIEmpServiceInstance().insert(vo));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

此时客户端的调用非常简单,就是调用业务层方法

image 20200815152117650

而且数据库中存在这样的值,我们再次执行这个方法

image 20200815152337955
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

以码平川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值