学习DAO设计模式(第八、九、十天)

(注:2020.06.17—2020.06.19 三天时间学习DAO设计模式大概花了五六个小时)

一、程序的分层:显示层+控制层+业务层+数据层(DAO)+数据库

一个业务层的操作需要与多个数据层操作共同完成,数据层完成的是一个个原子性操作,所有的操作业务在业务层中完成。

数据层:即数据访问层(Data Access Object,DAO),是专门进行数据库院子操作的。

业务层:即业务对象(Business Object,BO),又称服务层(Service),业务层核心目的是调用多个数据层操作以完成整体项目的业务设计。

二、在实际工作中,针对简单java类开发给出如下要求:

(1)考虑到日后程序有可能出现分布式应用的问题,所以简单java类必须实现java.io.Serializable接口;

(2)简单java类名称必须与表名保持一致;

扫描二维码关注公众号,回复: 11572848 查看本文章

(3)类中的属性不允许使用基本数据类型,都必须使用基本数据类型的包装类;

(4)类中可以定义多个构造方法,但是必须要保留一个无参构造方法;

(5)[可选]重写equals()、toString()、hashCode();

(6)类中的属性必须使用private对象,封装后的属性必须提供getter、 setter。

三、用户所提出的所有需求都应该划分到业务层,因为它指的是功能,而开发人员必须要根据业务层去划分数据层。

public class DatabaseConnection {
    private static final String DBDRIVER = "oracle. jdbc . driver . OracleDriver" ;
    private static final String DBURL = "jdbc: oracle: thin:@localhost :1521:mldn'
    private static final String DBUSER = 'scott" ;
    private static final String PASSWORD = "tiger" ;
    private Connection conn = null ;
    /**
    * 在构造方法里面为conn对象进行实例化,可以直接取得数据库的连接对象<br>
    * 由于所有的操作都是基于数据库完成的,如果数据库取得不到连接,那么也就意味着所有的操作都可以停止了
    */
    public DatabaseConnection() {
        try {
            Class.forName(DBDRIVER) ;
            this.conn = DriverManager.getConnection(DBURL, DBUSER, PASSWORD);
            } catch (Exception e) { //I虽然此处有异常,但是抛出的意义不大
            e. printStackTrace();
        }
    }
    /**
    *取得一个数据库的连接对象
    */
    @return Connection实例化对象
    public Connection getConnection() {
        return this.conn ;
    }
    /**
    *负责数据库的关闭
    */
    public void close() {
        if (this.conn != nu1l) {
        //表示现在存在有连接对象
        try {
            this.conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
​
}

整个的操作过程之中,DatabaseConnection只是无条件的提供有数据库连接,而至于说有多少个连接对象,它都不关心。

额外话题:从最早的DAO设计模式来讲实际上还会考虑到一个问题,多数据库间的移植问题。

此时就需要设置-一个专门的表示连接标准的接口,DatabaseConnectionFactory,dbc.properties: db=mysql]

四、开发Value Object

现在的程序严格来讲已经给出了四个层次。不同层次之间一定要进行数据的传递,但是既然要操作的是指定的数据表,所以数据的结构必须要与表的结构一一对应, 那么自然就可以想到简单Java类(po、to、pojo、vo、dto)。

不管有多少张表,只要是实体表,那么一定要写简单java类,而且不要试图一次性将所有表都转换到位。

import java. io. Serializable;
import java.util.Date;
@SuppressWarnings("seria1")
public class Emp implements Serializable {
    private Integer empno ;
    private String ename ;
    private String job ;
    private Date hiredate ;
    private Double sal ;
    private Double comm ;
    // setter、 getterl
}

五、开发数据层

数据层最终是交给业务层进行调用的,所以业务层必须知道数据层的执行标准,即:业务的操作方法,但是不需要知道它的具体实现。。

业务层--数据层标准--数据层--JDBC--数据库

开发数据层操作标准:不同层之间如果要进行访问,那么必须要提供有接口,以定义操作标注,那么对于数据层也是一样的,因为数据层的最终是要交给业务层执行,所以需要先定义出数据层的接口。

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

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

  • 既然不同的数据表的操作有可能使用不同的数据层开发,那么就针对数据表进行命名;

    ——如emp表,那么数据层的接口就应该定义为IEmpDAO;

  • 对于整个数据层的开发严格来讲就只有两类功能:。 ——数据更新:建议它的操作方法以doXxx0的形式命名,例如: doCreate()、 doUpdate()、 doRemove() ——数据查询。。。

public interface IEmpDAO {
    /**
    * 实现数据的增加操作
    * @param Vo包含了要增加数据的VO对象
    * @return 数据保存成功返回true,否则返回false
    * @throws Exception SQL 执行异常
    */
    public boolean doCreate(Emp vo) throws Exception ;
    /**
    * 实现数据的修改操作,本次修改是根据id进行全部字段数据的修改
    * @param Vo包含了要修改数据的信息,-定要提供有ID内容
    * @return数据修改成功返回true,否则返回false
    * @throws Exception SQL执行异常
    */
    public boolean doUpdate(Emp vo) throws Exception ;
    /**
    * 执行数据的批量删除操作,所有要删除的数据以Set集合的形式保存
    * @paramids包含了所有要删除的数据ID,不包含有重复内容
    * @return删除成功返回true ( 删除的数据个数与要删除的数据个数相同),否则返回false。
    * @throws Exception SQL执行异常
    */
    public boolean doRemoveBatch(Set<Integer> ids) throws Exception ;
    /**
    * 根据雇员编号查询指定的雇员信息
    * @param id要查询的雇 员编号
    * @return如果雇员信息存在,则将数据以V0类对象的形式返回,如果雇员数据不存在,则返回nu11
    */
    @throws Exception
    public Emp findById(Integer id) throws Exception ;
    
    /**
    * 根据雇员编号查询指定的雇员信息
    * @param id要查询的雇员编号
    * @return如果雇员信息存在,则将数据以V0类对象的形式返回,如果雇员数据不存在,则返回nu11
    * @throws Exception SQL执行异常
    public Emp findById(Integer id) throws Exception ;
    /**
    * 查询指定数据表的全部记录,并且以集合的形式返回
    * @retuFn如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
    * 如果没有数据,那么集合的长度为日(size() ==日,不是nu1l)
    * @throws Exception SQL执行异常
    */
    public List<Emp> findA11() throws Exception ;
    /**
    *分页进行数据的模糊查询,查询结果以集合的形式返回
    * @param currentPage 当前所在的页
    * @param lineSize 每页显示数据行数
    * @param column 要进行模糊查询的数据列
    * @param keyWord 模糊查询的关键字
    * @return 如果表中有数据,则所有的数据会封装为VO对象而后利用List集合返回,<br>
    * @throws Exception SQL执行异常
    */
    public List<Emp> findAllSp1it(Integer currentPage, Integer lineSize, String...
    
    /**
    * 进行模糊查询数据量的统计,如果表中没有记录统计的结果就是θ
    * @paramcolumn要进行模糊查询的数据列
    * @param keyWord 模糊查询的关键字
    * @return返回表中的数据量,如果没有数据返回0
    * @throws Exception SQL执行异常
    */
    public Integer getAllCount (String column, String keyWord) throws Exception ;
​
    
}
  • doCreate (Emp vo) bool ean

  • doUpdate (Emp vo) bool ean

  • doRemoveBatch (Set<Integer> ids) : boolean

  • findById() : Emp|

  • findA1l() : List<Emp>

  • findAllSplit(...) : List<Emp>

  • getAllCount(. ..) : Integer

五、数据层实现类

数据层需要被业务层调用,数据层需要进行数据库的执行(PreparedStatement),由于一个业务层需要执行多个数据层的调用,所以数据库的打开和关闭操作应该由业务层控制较为合理。

所有的数据层实现类要求保存在dao.impl子包下。范例: EmpDAOImpl 子类

六、数据层工厂类——DAOFactory

业务层要想进行数据层的调用,那么必须要取得IEmpDAO接口对象,但是不同层之间要想取得接口对象实例,则需要使用工厂设计模式。

package cn. mldn. factory;
import java. sq1. Connection;
import cn . mldn . dao. IEmpDAO;
import cn. mldn. dao. imp1. EmpDAOImp1;
public class DAOFactory {
    public static IEmpDAO getIEmpDAOInstance (Connection conn) {
        return new EmpDAOImp1(conn) ;
    }
}

使用工厂的特征就是外层不需要知道具体的字子类。

七、开发业务层

业务层是真正留给外部调用的,可能是控制层,或者是直接调用,既然业务层也是有不同层进行调用,所以业务层开发的首要任务就是定义业务层的操作标准。对于业务层方法的定义要写得有意义。

import cn. mldn. vo. Emp ;
​
/**
 * 定义emp表的业务层的执行标准,此类一定要负责数据库的打开与关闭操作
 * 此类可以通过DAOFactory类取得IEmpDAO接口对象
 * @author m1dn
 */
public interface IEmpService {
    /**
    * 实现雇员数据的增加操作,本次操作要调用IEmpDAO接口的如下方法: <br>
    * <li> 需要调用IEmpDAO . findById()方法,判断要增加数据的id是否已经存在;
    * <li>如果现在要增加的数据编号不存在则调用IEmpDAO . doCreate( )方法,返回操作的结果
    * @param vo包含了要增加数据的V0对象
    *
    * @return如果增加数据的ID重复或者保存失败返回false,否则返回true
    *
    * @throws Exception SQL执行异常
    * /
    public boolean insert(Emp vo) throws Exception ;
    /** 
    * 实现雇员数据的修改操作,本次要调用I EmpDAO . doUpdate( )方法,本次修改属于全部内容的修改;
    * @param Vo包含了要修改数据的V0对象
    * @return修改成功返回true,否则返回false
    * @throws Exception SQL执行异常
    */
    public boolean update(Emp vo) throws Exception;
    /**
    *
    * 执行雇员数据的删除操作,可以删除多个雇员信息,调用I EmpDAO . doRemoveBatch( )方法
    *
    * @param ids包含了全部要删除数据的集合,没有重复数据
    * @return删除成功返回true,否则返回false
    * @throws Exception SQL执行异常
    */
    public boolean delete(Set<Integer> ids) throws Exception ;
    /**
    * 根据雇员编号查找雇员的完整信息,调用IEmpDAO. findById()方法
    *
    * @param ids 要查找的雇员编号:
    * @return 如果找到了则雇员信息以VO对象返回,否则返回nu1l
    * @throws Exception SQL执行异常
    */
    public Emp get(int ids) throws Exception ;
    /**
    * 查询全部雇员信息,调用IEmpDAO . findA1l( )方法
    * @return查询结果以List集合的形式返回,如果没有数据则集合的长度为日
    * @throws Exception SQL 执行异常
    */
    public List<Emp> list() throws Exception ;
    
    /**
    * 实现数据的模糊查询与数据统计,要调用I EmpDAO接口的两个方法: <br>
    * <li>调用IEmpDAO. findA1lSplit( )方法,查询出所有的表数据,返回的List<Emp>;
    * <1i>调用IEmpDAO. getAllCount()方法,查询所有的数据量,返回的Integer;
    * @param currentPage 当前所在页.
    * @param lineSize每页显示的记录数
    * @param column 模糊查询的数据列
    * @param keyWord模糊查询关键字
    * @return本方法由于需要返回多种数据类型,所以使用Map集合返回,由于类型不统一,所以所有value的类型设置为Object,返回内容如下:
    * <li>key = allEmps, value = IEmpDAO.findA1lSplit()返回结果,List<Emp>;
    * <li>key = empCount, value = IEmpDAO.getAllCount()返回结果,Integer;
    * @throws Exception SQL执行异常
    */
    public Map<String, object> list(int currentPage, int lineSize, String column, String keyWord) throws Exception;
​
    
    
}
​

八、业务层实现类

业务层实现类的核心功能:

  • 负责控制数据库的打开和关闭,当存在了业务层对象后其目的就是为了操作数据库,即业务层对象实例化之后就必须准备好数据库连接;

  • 根据DAOFactory调用getIEmpDAOInstance0方法而后取得IEmpDAO接口对象。业务层实现类保存在dao.impl子包中。

package cn. mldn. service . impl;
import java. util. List;
public class EmpServiceImpl implements IEmpService {
    //在这个类的对象内部就提供有一个数据库连接类的实例化对象
    private DatabaseConnection dbc = new DatabaseConnection() ;
    @Override
    public boolean insert(Emp vo) throws Exception {
        try {
            if DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).findById(vo. getEmpno()) == null) {
                return DAOFactory.getIEmpDAOInstance(this.dbc.getConnection()).doCreate(vo);
            }
            return false;
        } catch (Exception e) {
            throw e ;
        } finally {
            this. dbc.close() ;
        }
    }
    @Override
    public boolean update(Emp vo) throws Exception {
        // TODO Auto-generated method stub
        return false;
    }
}
​

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

九、定义业务层工厂类——ServiceFactory

业务层最终依然需要被其它的层所使用,所以需要为其定义工厂类,该类也同样保存在factory子包下,如果从实际的开发来讲,业务层应该分为两种:

  • 前台业务逻辑:可以将其保存在service.front包中,工厂类:ServiceFrontFactory;

  • 后台业务逻辑:可以将其保存在service.back包中,工厂类:ServiceBackFactory。

package cn.mldn.factory;
import cn.mldn.service.IEmpService;+
import cn.mldn.service.impl.EmpService Imp1;
​
public class ServiceFactory {
    public static IEmpService getIEmpServiceInstance(){
        return new EmpServiceImp1();
    }
}
​

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

十、代码测试

因为最终的业务层是需要由用户去调用的,所以测试分为两种。

  1. 调用测试

    按照传统方式产生对象,而后调用里面的方式进行操作。保存在test子包内。调用业务层方法:

package cn . mldn. test;
import java . util . Date;
import cn. mldn. factory . ServiceFactory; 
import cn. mldn. vo. Emp;
public class TestEmpInsert {
    public static void main(String[] args) {
    Emp Vo = new Emp() ;
    vo. setEmpno(8889);
    vo. setEname( "陈冠祐" );
    vo. setJob("摄影师");
    vo. setHiredate(new Date());
    vo. setSal(10.0);
    vo. setComm(0.5);
    try {
        System.out.println(ServiceFactory.getIEmpServiceInstance().insert(vo);
    } catch (Exception e) {|
        e.printStackTrace();
    }
}
​

分页查询:

package cn. mldn. test;
import java. util . Iterator;
public class TestEmpSplit {
    @Suppres sWarnings ("unchecked" )
    public static void main(String[] args) {
        try {
            Map<String, object> map = ServiceFactory.getIEmpServiceInstance().list(2,5,"ename", "");
            int count = (Integer) map. get( " empCount"); 
            System. out. println("数据量: " + count) ;
            List<Emp> a1l = (List<Emp>) map. get("al1Emps");
            Iterator<Emp> iter = all. iterator();
            while (iter .hasNext()) {
            Emp Vo = iter. next();
            System. out . print1n(vo.getEname() + "," + vo.getJob());
        } catch (Exception e) {
            e. printStackTrace();
        }
    }
}
​

整个的操作流程客户端的调用非常的容易,不需要涉及到具体的数据存储细节。

    2. 利用junit进行测试

对于这种业务的测试,使用junit是最好的选择。 首先要选择测试的类或接口,现在选择好IEmpService接口进行测试。

十一、总结

1、理解分层的操作; 2、理解单表的CRUD的完整操作; 3、如果觉得需要进行提高,那么就把关系都编写熟练了。

猜你喜欢

转载自blog.csdn.net/keepfriend/article/details/106879053