DAO设计模式的介绍与实现

前言:哈哈,第一篇关于Java的博客了,暑假看了一些Java的设计模式,本来想着总结一下的,但是一耽误就到现在了,后面慢慢补上。今天我们来聊聊DAO

1、DAO是个什么东西呢?

看一下官方的介绍,DAO(Data Access Object,数据访问对象)的主要功能是数据操作,在程序的标准开发架构中属于数据层的操作。额,好像有点糊涂啊,用人类的语言解释一下也就是DAO是一种操作数据库的设计模式,也就是我们通过DAO这种设计模式,对于数据库的操作更加的方便管理,可扩展性更加的好。说到这里,可能也不是很明白,你把下面的代码都敲一遍,自然就明白了。

2、DAO的组成

上面说了DAO是什么东西,现在就来说说DAO的组成。有些地方说DAO是由五部分组成,有些地方说是由六部分组成。
五部分的说法是

数据库连接类: 连接数据库
VO实体类: JavaBean,里面一堆的setter和getter
DAO接口:  接口还能干啥,不就是让别人来实现吗,进行规范化管理。老板(接口)说了让你写报告,你要是不写就开除(报错)
DAO实现类: 员工写报告的的具体过程(打开电脑,***,关闭电脑,汇报)
DAO工厂类: 工厂不就是为了方便调用吗,要什么给什么。

六部分的说法是

数据库连接类: 连接数据库
VO实体类: JavaBean,里面一堆的setter和getter
DAO接口:  接口还能干啥,不就是让别人来实现吗,进行规范化管理。老板(接口)说了让你写报告,你要是不写就开除(报错)
DAO实现真正类: 员工自己不写,嘿嘿,去找小明帮他写,所以小明成为了真正的实现类
DAO的代理实现类: 员工这时候就是代理实现类
DAO工厂类: 工厂不就是为了方便调用吗,要什么给什么。

其实关于上面的两种组成部分,我还是比较赞同六部分组成的,因为这样更加的清晰化,数据和逻辑得到更进一步的分离,所以我下面就采用六部分来实现一个小例子。

3、通过图书的增删改查来看看这个神秘的玩意儿

1、创建数据库(自己使用的是MySQL),咱们就随便找几个字段意思一下,比较重点不在这里

create table books(
    bookid int auto_increment primary key,
    bookName varchar(50) not null,
    bookNumber int not null default 0,
    pubdate datetime not null,
    UNIQUE INDEX unique_id(bookid)
)

2、编写数据库的连接类
在编写数据库的连接类之前,我们可以想一想,我们这里采用的是MySQL数据库,如果其他地方使用Oracle或者SQL Server,那么我们的数据库连接类就需要进行修改,在Java中有一个设计模式的理念就是我们尽量不要进行代码的修改,通过增加代码来实现我们想要的功能(我忘记这个设计模式叫什么名字了,手动【尴尬】),因此我们通过让连接类实现一个接口的方式来连接数据库。我们建立一个DB包,在包中建立一个DatabaseConnection接口和一个MySQLConnection类
DatabaseConnection的代码如下

package DB;

import java.sql.Connection;
public interface DatabaseConnection {
    //  取得数据库的连接
    public Connection getConnection();
    //  关闭数据库的连接
    public void close();
}



MySQLConnection的代码如下

package DB;

import java.sql.Connection;
import java.sql.DriverManager;

public class MySQLConnection implements DatabaseConnection{
    //数据库连接驱动
    private static final String DBDRIVER = "com.mysql.jdbc.Driver";
    //数据库连接地址,我这里直接将数据库名字web放在后面了
    private static final String DBULR = "jdbc:mysql://localhost:3306/web";
    // 数据库用户名   
    private static final String USERNAME = "root";
    // 数据库密码    
    private static final String PASSWORD = "root";
    private Connection conn;
    // 取得数据库连接
    public Connection getConnection() throws Exception{
        try {
            // 加载驱动程序
            Class.forName(DBDRIVER);
            // 取得数据库连接,获得资源句柄
            this.conn = DriverManager.getConnection(DBULR,USERNAME,PASSWORD);
        }catch(Exception e) {
            throw e;
        }
        return this.conn;
    }
    // 关闭数据库连接  
    public void close() throws Exception{
        if(this.conn != null) {
            try{
                this.conn.close();
            }catch(Exception e) {
                throw e;
            }
        }
    }
}

3、数据库连接类写好了,咱们来写一下VO类吧,我们建一个VO的包,在里面建立一下Book类
book类的代码如下

package VO;

import java.util.Date;

public class Book {
    private int bookid;
    private String bookName;
    private int bookNumber;
    private Date pubdate;
    public int getBookid() {
        return bookid;
    }
    public void setBookid(int bookid) {
        this.bookid = bookid;
    }
    public String getBookName() {
        return bookName;
    }
    public void setBookName(String bookName) {
        this.bookName = bookName;
    }
    public int getBookNumber() {
        return bookNumber;
    }
    public void setBookNumber(int bookNumber) {
        this.bookNumber = bookNumber;
    }
    public Date getPubdate() {
        return pubdate;
    }
    public void setPubdate(Date pubdate) {
        this.pubdate = pubdate;
    }
}

4、接下来就是DAO接口类了,上面已经说过了,这就是老板安排的任务的汇总(进行数据库操作的所有方法)。因为我们要对图书进行增删改查,所以我们需要findById方法(查找),findAll(显示全部书籍),doUpdate(修改书籍),doDelete(删除书籍),doCreate(新增书籍)。我们建立一个DAO包,在这里面建立一个bookDAO的接口
bookDAO的代码如下

package DAO;

import java.sql.SQLException;
import java.util.List;

import VO.Book;

public interface BookDAO {
    //  查找某一本书籍
    public Book findById(int bookid) throws Exception;
    // 显示所有书籍
    public List<Book> findAll() throws Exception;
    // 修改书籍信息
    public boolean doUpdate(Book book) throws Exception;
    // 删除书籍信息
    public boolean doDelete(Book book) throws Exception;
    // 新增书籍信息
    public boolean doCreate(Book book) throws Exception;
}

5、接下来我们就是进行方法的具体实现,如果拆分成五部分的话,在这里就直接把方法实现了,但是因为我将其拆分成了六部分,所以我就先写真正的实现类,再写代理实现类。我们在DAO下面建立一个BookDAOImpl的类
BookDAOImpl的代码如下(代码相对比较多,但是逻辑比较简单)

package DAO;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import VO.Book;

public class BookDAOImpl implements BookDAO {
    private Connection conn;
    // 这里采用PreparedStatement进行预处理,主要是为了方式SQL注入
    // 关于网络安全,可以看我GitHub上面的一个文章
    // https://github.com/deng1234/webSecurity
    private PreparedStatement pstmt;
    // 在代理实现类中进行对象实例化的时候获得连接数据库的资源句柄    
    public BookDAOImpl(Connection conn) {
        this.conn = conn;
    }
    @Override
    // 根据id查找   
    public Book findById(int bookid) throws SQLException{
        Book book = new Book();
        String sql = "SELECT bookid, bookName, bookNumber, pubdate FROM books WHERE bookid = ?";
        try {
            this.pstmt = this.conn.prepareStatement(sql);
            this.pstmt.setInt(1, bookid);
            ResultSet rs = (ResultSet) this.pstmt.executeQuery();
            if(rs.next()) {
                book.setBookid(rs.getInt(1));
                book.setBookName(rs.getString(2));
                book.setBookNumber(rs.getInt(3));
                book.setPubdate(rs.getDate(4));
            }
        } catch (SQLException e) {
            throw e;
        }
        this.pstmt.close();
        return book;
    }

    @Override
    // 列出所有书籍
    public List<Book> findAll() throws SQLException {
        List<Book> books = new ArrayList<Book>();
        Book book;
        String sql = "SELECT bookid, bookName, bookNumber, pubdate FROM books";
        try {
            this.pstmt = this.conn.prepareStatement(sql);
            ResultSet rs = (ResultSet) this.pstmt.executeQuery();
            while(rs.next()) {
                book = new Book();
                book.setBookid(rs.getInt(1));
                book.setBookName(rs.getString(2));
                book.setBookNumber(rs.getInt(3));
                book.setPubdate(rs.getDate(4));
                books.add(book);
            }
        } catch (SQLException e) {
            throw e;
        }
        this.pstmt.close();
        return books;
    }

    @Override
    // 修改书籍信息
    public boolean doUpdate(Book book) throws SQLException {
        boolean flag = false;
        String sql = "UPDATE books SET bookName = ?, bookNumber = ?, pubdate = ? WHERE bookid = ?";
        try {
            this.pstmt = this.conn.prepareStatement(sql);
            this.pstmt.setString(1, book.getBookName());
            this.pstmt.setInt(2, book.getBookNumber());
            this.pstmt.setDate(3, new java.sql.Date(book.getPubdate().getTime()));
            this.pstmt.setInt(4, book.getBookid());
            if(this.pstmt.executeUpdate() > 0) {
                flag = true;
            }
        } catch (SQLException e) {
            throw e;
        }
        this.pstmt.close();
        return flag;
    }

    @Override
    // 删除书籍信息
    public boolean doDelete(Book book) throws SQLException {
        boolean flag = false;
        String sql = "DELETE FROM books WHERE bookid = ?";
        try {
            this.pstmt = this.conn.prepareStatement(sql);
            this.pstmt.setInt(1, book.getBookid());
            if(this.pstmt.executeUpdate() > 0) {
                flag = true;
            }
        } catch (SQLException e) {
            throw e;
        }
        this.pstmt.close();
        return flag;
    }

    @Override
    // 新增书籍
    public boolean doCreate(Book book) throws SQLException {
        boolean flag = false;
        String sql = "INSERT INTO books (bookName, bookNumber, pubdate) "
                + "values(?, ?, ?)";
        try {
            this.pstmt = this.conn.prepareStatement(sql);
            this.pstmt.setString(1, book.getBookName());
            this.pstmt.setInt(2, book.getBookNumber());
            this.pstmt.setDate(3, new java.sql.Date(book.getPubdate().getTime()));
            if(this.pstmt.executeUpdate() > 0) {
                flag = true;
            }
        } catch (SQLException e) {
            throw e;
        }
        this.pstmt.close();
        return flag;
    }

}

6、咱们接下来就写DAO的代理实现类,在DAO的包下面建立一个BookDAOProxy类,因为不管是代理,还是真正去实现的,接口中(老板)的方法都是需要去做的,所以我们在这里面都需要实现BookDAO接口
BookDAOProxy类的代码为

package DAO;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import DB.MySQLConnection;
import VO.Book;

public class BookDAOProxy implements BookDAO{
    private MySQLConnection conn = null;
    private BookDAO dao;
    public BookDAOProxy() throws Exception {
        this.conn = new MySQLConnection();
        // 在这里对真正的DAO实现内进行实例化       
        this.dao = new BookDAOImpl(this.conn.getConnection());
    }

    @Override
    // 书籍查找
    public Book findById(int bookid) throws Exception {
        Book book = new Book();
        try {
            book = this.dao.findById(bookid);
        }catch(SQLException e) {
            throw e;
        }finally {
            // 关闭数据库
            this.conn.close();
        }
        return book;
    }

    @Override
    // 列出所有书籍
    public List<Book> findAll() throws Exception {
        List<Book> books = new ArrayList<Book>();
        try {
            books = this.dao.findAll();
        }catch(Exception e) {
            throw e;
        }finally {
            this.conn.close();
        }
        return books;
    }

    @Override
    public boolean doUpdate(Book book) throws Exception {
        boolean flag = false;
        try {
            if(this.dao.findById(book.getBookid()) != null) {
                flag = this.dao.doUpdate(book);
            }
        }catch(Exception e) {
            throw e;
        }finally {
            this.conn.close();
        }
        return flag;
    }

    @Override
    public boolean doDelete(Book book) throws Exception {
        boolean flag = false;
        try {
            flag = this.dao.doDelete(book);
        }catch(Exception e) {
            throw e;
        }finally {
            this.conn.close();
        }
        return flag;
    }

    @Override
    public boolean doCreate(Book book) throws Exception {
        boolean flag = false;
        try {
            flag = this.dao.doCreate(book);
        }catch(Exception e) {
            throw e;
        }finally {
            this.conn.close();
        }
        return flag;
    }

}

7、挺住,我们马上就迎来最后一部分啦,建立一个工厂类。为什么进行工厂类呢,如果不进行工厂化处理的时候,我们调用方法需要对BookDAOProxy进行对象实例化,然后再调用其中的方法,不管在哪里调用,都需要进行对象实例化。如果有一天我们需要修改代理类,哈哈,你就需要去每一个地方修改(^__^),虽然修改的可能性不大哈。但是如果我们进行工厂类的封装,调用直接通过工厂类取得其实例化,并且如果要要换一个代理类,直接修改即可。我们建立一个FACTORY的包,然后在下面建立一个DAOFactoty的类
DAOFactory的代码为

package FACTORY;

import DAO.BookDAO;
import DAO.BookDAOProxy;

public class DAOFactory {
    public static BookDAO getBookDAOInstance() throws Exception {
        return new BookDAOProxy();
    }
}

4、折腾了半天,我们总得测试一下,看看写的正确吧

我们建立一个Test包,在里面建立一个doCreate的类测试数据插入,doUpdate测试数据修改,doDelete测试数据删除,findAll数据显示,finById数据查找 。
数据插入方法测试的测试

package Test;

import FACTORY.DAOFactory;
import VO.Book;

public class doCreate {
    public static void main(String args[]) throws Exception {
        Book book = new Book();
        try {
            book.setBookName("Java特种兵");
            book.setBookNumber(1);
            book.setPubdate(new java.util.Date());
            boolean flag = DAOFactory.getBookDAOInstance().doCreate(book);
            System.out.println(flag);//true则是成功,false则是失败
        }catch(Exception e) {
            System.out.println(e);
        }
    }
}



数据查找方法测试代码

package Test;

import FACTORY.DAOFactory;
import VO.Book;

public class finById {
    public static void main(String args[]) throws Exception {
        Book book = new Book();
        try {
            book = DAOFactory.getBookDAOInstance().findById(1);
            System.out.println(book.getBookName()+"--"+book.getBookNumber()+"--"+book.getPubdate());
        }catch(Exception e) {
            System.out.println(e);
        }
    }
}



数据修改方法测试代码

package Test;

import FACTORY.DAOFactory;
import VO.Book;

public class doUpdate {
    public static void main(String args[]) throws Exception {
        Book book = new Book();
        try {
            book.setBookid(1);
            book.setBookName("Java特种兵");
            book.setBookNumber(3);
            book.setPubdate(new java.util.Date());
            boolean flag = DAOFactory.getBookDAOInstance().doUpdate(book);
            System.out.println(flag);
        }catch(Exception e) {
            System.out.println(e);
        }
    }
}



数据删除方法代码测试

package Test;

import FACTORY.DAOFactory;
import VO.Book;

public class doDelete {
    public static void main(String args[]) throws Exception {
        Book book = new Book();
        try {
            book.setBookid(1);
            boolean flag = DAOFactory.getBookDAOInstance().doDelete(book);
            System.out.println(flag);
        }catch(Exception e) {
            System.out.println(e);
        }
    }
}



显示所有数据方法代码测试

package Test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import FACTORY.DAOFactory;
import VO.Book;

public class findAll {
    public static void main(String args[]) throws Exception {
        List<Book> books = new ArrayList<Book>();
        Book book = new Book();
        try {
            books = DAOFactory.getBookDAOInstance().findAll();
            Iterator<Book> iter = books.iterator();
            while(iter.hasNext()) {
                book = iter.next();
                System.out.println(book.getBookName()+"--"+book.getBookNumber()+"--"+book.getPubdate());
            }
        }catch(Exception e) {
            System.out.println(e);
        }
    }
}

详细代码可以在我的Github上面查看

(完)

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页