前言:哈哈,第一篇关于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上面查看
(完)