DAO模式的使用

简介: 最近在上Servlet的时候,穿插讲了一些DAO设计模式,要求实现对学生表的CRUD,以下完整范例项目Students作为一个回顾。一.设计架构原理:直接使用课件原图image.

最近在上Servlet的时候,穿插讲了一些DAO设计模式,要求实现对学生表的CRUD,以下完整范例项目Students作为一个回顾。

一.设计架构原理:

直接使用课件原图


img_e3f69359bdc66ceab4cb243368f47234.png
image.png

完整的DAO模式其实横跨了BO,DAO,DataBase三层,层与层之间的调用以及访问通过接口访问,实现了分层设计,主要有以下几个类:
实体类javaBean:是各层的底层媒介 通常存放在VO包下
DataBaseConnection: 数据层连接数据库驱动程序 数据层与数据库(DataBase)通信基础 通常存放在dbc包下
IXXXDAO :数据层与业务层接口 数据层与业务层通信基础 通常存放在DAO包下
XXXDAOImpl: 数据层实现类(继承IXXXDAO)具体实现CRUD操作 通常存放在impl包下
DAOFactory:数据层工厂类 业务层对数据层进行调用,必须有DAO包下的IXXXDAO接口,但不同层想取得接口对象实例,需要使用工厂设计模式 通常存放在factory包下
IXXXService: 业务层与其他层接口 实现业务层与数据层等通信基础 通常存放在service包下
XXXServiceImpl: 业务层实现类 通常放在impl包下
ServiceFactory :业务层工厂类 用来获得业务层接口 供控制层调用 通常放在Factory包下

二.代码实现

完整的项目结构如下:


img_9c691b579f5ebb0ab6b5454126fd0e6c.png
SO[NZ)UYGBMVS]L~{AN`)@E.png

根据下图 我们从DataBase数据库开始开发 从后往前


img_bc1fce5c7a6496408bf2f1f149ad8ab9.png
CPJ5L$D3PG%}HH{52UU6}IP.png

1.MySQL建student表


img_1e525f891cf579555a119c80c8a55eac.png
image.png

1.Student.class 实体类映射表的字段

package com.sl.vo;
//所有的javabean(简单java类保存在VO包中)
//对应数据库的表 映射 Value Object 简单java类的名称必须与表的名称对应 例如student_info对应StudentInfo Student对应Student

public class Student {
    private int idStudent;
    private String password;
    private int sex;
    private String credit;
    private String favourite;
    private String introduction;
    
    public int getIdStudent() {
        return idStudent;
    }

    public void setIdStudent(int idStudent) {
        this.idStudent = idStudent;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public String getCredit() {
        return credit;
    }

    public void setCredit(String credit) {
        this.credit = credit;
    }

    public String getFavourite() {
        return favourite;
    }

    public void setFavourite(String favourite) {
        this.favourite = favourite;
    }

    public String getIntroduction() {
        return introduction;
    }

    public void setIntroduction(String introduction) {
        this.introduction = introduction;
    }
}

2.DataBaseConnection:数据库驱动连接

package com.sl.dbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.*;
//在本类的构造方法里要进行数据库的驱动加载和数据库的连接取得 不进行数据库操作
//数据层与数据库连接
/**
 *
 * @author sl
 */
public class DataBaseConnection {

    
    private static final String DBDRIVER="com.mysql.jdbc.Driver";
    private static final String DBURL="jdbc:mysql://localhost/mydb";//这里是Oracle数据库的写法
    private static final String DBUSER="root";
    private static final String PASSWORD="SL886886";
    private Connection conn=null;
    //在构造方法里为conn对象实例化,可以直接取得数据库的连接对象
    public DataBaseConnection() {
        try{
            //第一步 数据库驱动程序
        Class.forName(DBDRIVER);
            //第二部 数据库连接
        this.conn=DriverManager.getConnection(DBURL,DBUSER,PASSWORD);
            //第三步 进行数据库操作
//            Statement stmt=conn.createStatement();
//            String sql = "INSERT INTO Student(idStudent, password, sex, credit,favourite,introduction) "  + "VALUES(5,'556', 1,'体育', '音乐', '我是王五')";
//             int len=stmt.executeUpdate(sql);//执行sql 返回更新的行数
//             System.out.println("影响的行数"+len);
//            //第四步 关闭数据库
//            conn.close();
        }catch(Exception e){
        e.printStackTrace();
        }
    }
    //取得一个数据库的连接对象 返回一个Connection的实例对象
    public Connection getConnection(){
        return this.conn;
    }
    //负责数据库的关闭
    public void close(){
        if(this.conn!=null){//表示现在存在有我们的连接对象
            try{
                this.conn.close();
            }catch(SQLException e){
            e.printStackTrace();
            }
        }
    }
}

3.IStudentDAO:数据层接口

package com.sl.dao1;
import com.sl.vo.Student;
import java.util.*;
//定义Student表数据层的操作标准(以接口形式)
/**
 *
 * @author sl
 */
//数据层与业务层通信标准 接口形式实现
public interface IStudentDAO {
    //数据的增加操作
    //VO包含了要增加数据的VO对象
    //增加成功返回true 否则返回false
    public boolean doCreate(Student vo) throws Exception;//doUpdata doEdlete等具体的增删改查
    //数据的修改操作 我们本次的修改是根据id进行全部数据的修改
    //VO包含了我们要修改数据的信息 一定要包含id内容
    //修改成功返回true 否则返回false
    public boolean doUpdate(Student vo) throws Exception;
    //数据的批量删除操作 所有要删除的数据以set集合形式保存
    //Ids包含了所要要删除的数据ID,不包含重复内容
    //删除成功返回true(删除的数据个数与传入的数据个数相同返回true),否则返回false
    public boolean doRemoveBatch(Set<Integer> ids) throws Exception;
    //根据雇员/学生编号查询指定的雇员信息
    //id是要查询的雇员/学生编号
    //如果雇员信息存在 则将VO类以对象的形式返回 如果雇员信息不存在 则返回空
    public Student findById(Integer id) throws Exception;//如果雇员存在 则返回雇员,如果雇员不存在,则返回null
    //查询指定数据表的全部记录 并且以集合形式返回
    //如果表中有数据,那么数据库层的数据在数据层中就会封装成VO对象 利用List集合返回 如果没有数据 那么集合的长度为0(size()==0,而不是null) 
    public List<Student> findAll()throws Exception;
    //分页进行数据的模糊查询,结果以集合的形式返回
    //currentPage 当前所在的页
    //lineSize 每页显示的数据函数
    //column 要进行模糊查询的数据列
    //keyWord 模糊查询的关键字
    //如果表中有数据,那么数据库层的数据在数据层中就会封装成VO对象 利用List集合返回 如果没有数据 那么集合的长度为0(size()==0,而不是null) 
    public List<Student> findAllSplit(Integer currentPage,Integer lineSize,String column,String keyWord) 
            throws Exception;//如果表中有数据 则所有对象封装为VO对象装入List中返回
    
    //进行模糊查询数量的统计,如果表中没有记录 统计的结果就是0
     //column 要进行模糊查询的数据列
    //keyWord 模糊查询的关键字
    //返回表中的数据量 如果表中没有数据 则返回0
    public Integer getAllCount(String column,String keyWord)throws Exception;
}
  1. StudentDAOImpl:数据层接口实现类
package com.sl.dao.impl;
//具体实现类

import com.sl.dao1.IStudentDAO;
import com.sl.vo.Student;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
*
* @author sl
*/
//数据层具体实现增删改查操作类,由于我们最好自己在业务层定义数据库开关 所以在数据层要有Connection类对象实参 具体的开关在业务层实现 传入Connection对象实参
//VO对象作为了数据层 业务层等等层的底层媒介
public class StudentDAOImpl implements IStudentDAO{//具体实现类 覆盖增删改查doCreat(),doUpdate等
   private Connection conn;
   private PreparedStatement pstmt;

  public StudentDAOImpl(Connection conn) {    //由外部传入Connection对象
      this.conn = conn;
  }
  //增加 数据更新
  @Override
  public boolean doCreate(Student vo) throws Exception {//vo只是作为了一个媒介 要想理解此次操作 还是看pstmt.setXXX是用来增加数据的 对应数据库的操作
      String sql="INSERT INTO Student(idStudent,password,sex,credit,favourite,introduction) VALUES(?,?,?,?,?,?)";
      this.pstmt=conn.prepareStatement(sql);
      pstmt.setInt(1, vo.getIdStudent());
      pstmt.setString(2, vo.getPassword());
      pstmt.setInt(3, vo.getSex());
      pstmt.setString(4, vo.getCredit());
      pstmt.setString(5, vo.getFavourite());
      pstmt.setString(6, vo.getIntroduction());
      return this.pstmt.executeUpdate()>0;//如果为真 就是执行了操作 返回true1 否则返回false0
  }
  //更新 数据更新
  @Override
  public boolean doUpdate(Student vo) throws Exception {
      String sql="UPDATE Student password=?,sex=?,credit=?,favourite=?,introduction=? WHERE idStudent=?";
      this.pstmt=conn.prepareStatement(sql);
      pstmt.setString(1, vo.getPassword());
      pstmt.setInt(2, vo.getSex());
      pstmt.setString(3, vo.getCredit());
      pstmt.setString(4, vo.getFavourite());
      pstmt.setString(5, vo.getIntroduction());
      pstmt.setInt(6, vo.getIdStudent());
      return this.pstmt.executeUpdate()>0;//如果为真 就是执行了操作 返回true1 否则返回false0

  }
  //批量删除 数据更新
  @Override
  public boolean doRemoveBatch(Set<Integer> ids) throws Exception {
      if(ids==null||ids.size()==0){//如果没有要删除的对象id(即表中idStudent)
          return false;
      }
      StringBuffer sql=new StringBuffer();//拼凑字符串 拼凑sql语句
      sql.append("DELETE FROM Student WHERE idStudent IN(");//append用来正式添加进拼凑的语句中
      Iterator<Integer> iter=ids.iterator();
      while (iter.hasNext()) {
          sql.append(iter.next()).append(",");//添加进ids整型集合中的整型数字 每个数字用","隔开
      }
      sql.delete(ids.size()-1, ids.size());//删除最后一个逗号
      sql.append(")");//加上IN()的结尾小括号
      this.pstmt=this.conn.prepareStatement(sql.toString());//toString将StringBuffer变为String
      return this.pstmt.executeUpdate()==ids.size();//删除的数量是否等于id集合的长度
  }
//根据id查询 数据查询 成功返回VO类对象 失败返回null
  @Override
  public Student findById(Integer id) throws Exception {
      Student vo=null;
      String sql="SELECT idStudent,password,sex,credit,favourite,introduction FROM Student WHRER idStudent=?";
      this.pstmt=this.conn.prepareStatement(sql);
      this.pstmt.setInt(1, id);//根据传入的实参来删除对象
      ResultSet rs=this.pstmt.executeQuery();//对数据库进行查询 有结果返回
      if(rs.next()){//逐行读数据 虽然只有一行
      vo=new Student();
      vo.setIdStudent(rs.getInt(1));//逐列读出
      vo.setPassword(rs.getString(2));
      vo.setSex(rs.getInt(3));
      vo.setCredit(rs.getString(4));
      vo.setFavourite(rs.getString(5));
      vo.setIntroduction(rs.getString(6));
      }
      return vo;
  }
//查询全部数据 数据查询
  @Override
  public List<Student> findAll() throws Exception {
              List<Student> all=new ArrayList<Student>();
              String sql="SELECT idStudent,password,sex,credit,favourite,introduction FROM Student";
              this.pstmt=this.conn.prepareStatement(sql);
              ResultSet rs=this.pstmt.executeQuery();//对数据库进行查询 有结果返回
              while(rs.next()){//逐行读数据 虽然只有一行
                  Student vo=new Student();;
              vo.setIdStudent(rs.getInt(1));//逐列读出
              vo.setPassword(rs.getString(2));
              vo.setSex(rs.getInt(3));
              vo.setCredit(rs.getString(4));
              vo.setFavourite(rs.getString(5));
              vo.setIntroduction(rs.getString(6));
              all.add(vo);//将从数据库返回的数据保存在底层媒介后 往泛型集合中加一个实例化对象
      }
              return all;
  }
//查询全部数据并分页 数据查询
  @Override
  public List<Student> findAllSplit(Integer currentPage, Integer lineSize, String column, String keyWord) throws Exception {
        List<Student> all=new ArrayList<Student>();
              String sql="SELECT * FROM "
                      + " SELECT idStudent,password,sex,credit,favourite,introduction FROM Student"
                      +" WHERE "+column+" LIKE ? AND ROWNUM<=?) temp"
                      +" WHERE temp.rn>? " ;
              this.pstmt=this.conn.prepareStatement(sql);
              pstmt.setString(1, "%"+keyWord+"%");
              pstmt.setInt(2, currentPage*lineSize);
              pstmt.setInt(3, (currentPage-1)*lineSize);
              ResultSet rs=this.pstmt.executeQuery();//对数据库进行查询 有结果返回
              while(rs.next()){//逐行读数据 虽然只有一行
                  Student vo=new Student();;
              vo.setIdStudent(rs.getInt(1));//逐列读出
              vo.setPassword(rs.getString(2));
              vo.setSex(rs.getInt(3));
              vo.setCredit(rs.getString(4));
              vo.setFavourite(rs.getString(5));
              vo.setIntroduction(rs.getString(6));
              all.add(vo);//将从数据库返回的数据保存在底层媒介后 往泛型集合中加一个实例化对象
      }
              return all;    }

  @Override
  public Integer getAllCount(String column, String keyWord) throws Exception {
      String sql="SELECT COUNT(idStudent) FROM Student WHERE "+column+"LIKE ?";
      this.pstmt=this.conn.prepareStatement(sql);
      this.pstmt.setString(1, "%"+keyWord+"%");
      ResultSet rs=this.pstmt.executeQuery();
      if(rs.next()){
          return rs.getInt(1);
      }
      return null;
  }
  
}

5.DAOFactory:供业务层调用的工厂类
package com.sl.dao.factory;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
import com.sl.dao.impl.StudentDAOImpl;
import com.sl.dao1.IStudentDAO;
import java.sql.Connection;
/**
 *
 * @author sl
 */
//数据层工厂类 为了方便业务层对数据层进行操作 关闭开启数据库
//使用工厂类的特征就是不需要知道具体的子类(第三方接口也是这样 只负责传参 不关心具体的实现类)即业务层是看不见具体的实现类StudentDAOImpl
//除此之外的VO类,IStudentDAO,Connection等都能看见
public class DAOFactory{//接口集合
    public static IStudentDAO getIStudentDAOInstance(Connection conn){//由外部传入形参 
        return new StudentDAOImpl(conn);//双重形参
    }
    
}

6.IStudentService:业务层通信基础 业务层接口

package com.sl.service;

import com.sl.vo.Student;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author sl
 */
//业务层通信标准 业务层接口 并且继承此接口的类在业务层一定要负责数据库的打开和关闭操作
//此外继承此接口的类可以通过DAOFactory类取得IEmpDAO接口对象
//业务层能用int还是使用int型 不用包装类 便于区分
public interface IStudentService {
    //实现学生数据的增加操作
    //本次操作调用IStudentDAO接口的如下方法
    //调用IStudentDAO.findById()方法看学生id是否存在
    //如果不存在则调用IStudentDAO.doCreate()方法增加数据
    //@return 如果Id存在或者保存失败,返回false,否则返回true
    public  boolean insert(Student vo)throws Exception;
    
    //实现学生数据的修改操作
    //本次调用IStudentDAO的doUpdate()方法
    //@return 修改成功返回true,否则返回false
     public  boolean update(Student vo)throws Exception;
     
     //实现学生数据的批量删除操作
     //本次调用IStudentDAO中的doRemoveBatch方法
     //@param ids包含了全部要删除数据的集合 没有重复数据
     //return 删除成功返回true 否则返回false
      public  boolean delete(Set<Integer> ids)throws Exception;
      
      //根据学生的id编号 查找学生信息
      //本次调用了IStudentDAO中的findById()方法
      //@param id表明要查找的学生编号
      //@return 如果找到了学生信息 以Student vo类对象返回,否则返回null
       public  Student get(int ids)throws Exception;
       
       //查询全部学生信息 调用IStudentDAO.findAll()方法
       //@return 查询结果以list集合形式返回,如果没有数据,集合长度为0
       public List<Student> list() throws Exception;
       
       /**
        * 实现数据的模糊查询与数据统计
        * 要调用IStudentDAO.findAllSplit()方法,查询所有的表数据,返回的List<Student>
        * 调用IStudentDAO.getAllCount()方法,查询所有的数据量,返回Integer
        * @param currentPage 当前所在页
        * @param lineSize 每页显示的记录数目
        * @param column 模糊查询的数据列
        * @param keyWord 模糊查询的关键字
        * @return 本方法由于需要返回多种数据类型,所以使用Map集合返回,由于类型不同意,所以所有Value的类型设置为Object
        * 如果key=allStudents,value=IStudentDAO.findAllSplit()方法返回结果 List<Student>
        * 如果key=StudentCount value=IStudentDAO.getAllCount()返回结果 Integer
        * @throws Exception 
        */
       public Map<String,Object> list(int currentPage,int lineSize,String column,String keyWord) throws Exception;
}

7.StudentServiceImpl:业务层实现类

public class StudentServiceImpl implements IStudentService{
    //数据库连接类,实例化以后就连接上了数据库 所以我们之后的方法 一定有finally 用来关闭数据库 this.dbc.close
    public DataBaseConnection dbc=new DataBaseConnection();
    @Override
    public boolean insert(Student vo) throws Exception {
            try {
                //首先 由业务层传入的Connection对象负责开关 双重形参 并且返回的IStudentDAO对象调用其findById方法 看是否学生编号为空
            if(DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).findById(vo.getIdStudent())==null){
                //学生id编号为空 我们就能进行增加操作了 以上以下为代码链
                return DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).doCreate(vo);
            }
            return false;
        } catch (Exception e) {
            throw e;
        }finally{
             this.dbc.close();
            }
    }

    @Override
    public boolean update(Student vo) throws Exception {
     try {
            return DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).doUpdate(vo);
        } catch (Exception e) {
            throw e;
        }finally{
             this.dbc.close();
            }
    }

    @Override
    public boolean delete(Set<Integer> ids) throws Exception {
     try {
            return DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).doRemoveBatch(ids);       
        } catch (Exception e) {
            throw e;
        }finally{
             this.dbc.close();
            }
    }

    @Override
    public Student get(int ids) throws Exception {
     try {
            return DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).findById(ids);
        } catch (Exception e) {
            throw e;
        }finally{
             this.dbc.close();
            }
    }

    @Override
    public List<Student> list() throws Exception {
     try {
           return DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).findAll();
        } catch (Exception e) {
            throw e;
        }finally{
             this.dbc.close();
            }
    }

    @Override
    public Map<String, Object> list(int currentPage, int lineSize, String column, String keyWord) throws Exception {
     try {
            Map<String,Object> map=new HashMap<String,Object>();
            map.put("allStudents", DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).findAllSplit(currentPage, lineSize, column, keyWord));
            map.put("StudentCount", DAOFactory.getIStudentDAOInstance(this.dbc.getConnection()).getAllCount(column, keyWord));
            return map;
        } catch (Exception e) {
            throw e;
        }finally{
             this.dbc.close();
            }
    }
    
}

8.ServiceFactory:业务层工厂类

//业务层工厂类 用来获得业务层接口
public class ServiceFactory {
    public static IStudentService getIStudentServiceInstance(){
    return new StudentServiceImpl();
    }
}

三.代码测试:

写个增加数据的调用测试

package com.sl.test;

import com.sl.dao.factory.ServiceFactory;
import com.sl.vo.Student;

/**
 *
 * @author sl
 */
public class TestStudentInsert {
    public static void main(String[] args) {
        Student vo=new Student();
        vo.setIdStudent(3);
        vo.setPassword("567");
        vo.setSex(0);
        vo.setCredit("university");
        vo.setFavourite("PE");
        vo.setIntroduction("wangwu");
        try {//不同层操作 使用try catch
            System.err.println(ServiceFactory.getIStudentServiceInstance().insert(vo));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

结果:


img_b42e745ab47719922e2af9e4d4f71f94.png
KUXG`9T939M2}XFYTI7B5DK.png

搞定~

相关文章
|
4月前
|
Java 数据库连接 Maven
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
文本,使用SpringBoot工程创建一个Mybatis-plus项目,Mybatis-plus在编写数据层接口,用extends BaseMapper<User>继承实体类
|
6月前
|
Java 数据库连接 mybatis
MyBatis中Mapper接口和dao区别是什么?
MyBatis中Mapper接口和dao区别是什么?
177 0
|
6月前
|
Java 数据库连接 mybatis
MyBatis的Dao层实现方式
MyBatis的Dao层实现方式
47 0
|
6月前
|
Java 数据库连接 mybatis
Mapper代理开发
Mapper代理开发
39 0
|
Java 数据库连接 mybatis
MyBatis实现基于Mapper接口代理Dao的CURD
MyBatis实现基于Mapper接口代理Dao的CURD
|
Java 数据库连接 程序员
Mybatis Mapper代理开发Dao层
Mybatis Mapper代理开发Dao层
195 0
|
SQL XML 缓存
Mybatis中Dao接口的工作原理
Mybatis中Dao接口的工作原理
190 0
|
SQL Java 数据库连接
MyBatis:接口代理方式实现Dao
MyBatis:接口代理方式实现Dao
281 0
MyBatis:接口代理方式实现Dao
|
SQL Java 数据库连接
MyBatis - DAO接口不需要实现类分析(下)
MyBatis - DAO接口不需要实现类分析(下)
259 0
MyBatis - DAO接口不需要实现类分析(下)
|
XML SQL Java
MyBatis - DAO接口不需要实现类分析(上)
MyBatis - DAO接口不需要实现类分析(上)
258 0
MyBatis - DAO接口不需要实现类分析(上)