代码之家  ›  专栏  ›  技术社区  ›  Todd Owen

为什么要将DAO层置于持久层之上(如JDO或Hibernate)

  •  32
  • Todd Owen  · 技术社区  · 16 年前

    public class Book {
        // Book description in various languages, indexed by ISO language codes
        private Map<String,BookDescription> descriptions;
    }
    

    如果我要引入一个“数据访问层”,编写一个像BookDao这样的类,并将所有JDO代码封装在其中,那么JDO对子对象的透明加载不会绕过数据访问层吗?为了保持一致性,是否应该通过某个BookDescriptionDao对象(或BookDao.loadDescription方法)加载并持久化所有BookDescription对象?然而,以这种方式进行重构会使操作模型变得不必要的复杂。

    所以我的问题是,直接在业务层调用JDO(或Hibernate,或任何您喜欢的ORM)有什么错?它的语法已经相当简洁,并且与数据存储无关。将其封装在数据访问对象中有什么好处(如果有的话)?

    10 回复  |  直到 16 年前
        1
  •  12
  •   KLE rslite    16 年前

    你提出了一些观点。但我仍然使用Dao层,原因如下:

    1. 数据库访问是 对远程系统的调用

    2. 有时,持久化操作只是加载/保存/删除对象。一个唯一的DAO(或一个超类;考虑泛型)可以对此负责,因此您不必一次又一次地对这些方法进行编码。
      但通常情况下,你也有 特定需求,例如运行ORM不会自动创建的特定请求 . 在那里,您可以使用特定的Dao方法来编写您的特定需求(重用通常是可能的)。
      在同一层中具有常规和特定的需求允许重用(例如,拦截可以确保在需要时打开/提交数据库连接)。

        2
  •  11
  •   8bitjunkie Vikram    14 年前

    随着时间的推移,“道”已经失去了它的意义。

    在J2EE时代,当它成为一种流行模式时,DAO是一种可以同时满足多个数据源(一个供应商的数据库、另一个供应商的数据库、一个文件)的类,并提供一个单独的位置来封装查询以进行数据通信。

    有大量的重用空间,因此特定实体的DAO对象可以很好地扩展包含可重用内容的抽象DAO,而抽象DAO本身实现了DAO接口。

    在J2EE/EJB之后,DataMapper和DataSource模式(或对于简单系统,ActiveRecord)开始流行,以执行相同的角色。然而,DAO成了任何涉及持久性的对象的时髦词汇。

    有了ORM/JPA,真正的J2EE时代DAO的大部分基本原理都是现成的。

    对于后一种数据源模式,JPA的EntityManager类似于数据源,但通常通过PersistenceUnit XML定义提供,并通过IoC实例化。

    曾经存在于DAO或Mapper中的CRUD方法现在可以使用Repository模式提供一次。不需要AbstractDAO——ORM产品足够聪明,可以接受Object()并知道它在哪里持久化它。

        3
  •  10
  •   Preet Sangha    16 年前

    这取决于层的目标是什么。您在中添加了一个抽象,以提供一组不同于另一组的语义。一般来说,有更多的层次来简化一些事情,例如未来维护的开发。但它们还有其他用途。

    例如,ORM代码上的DAO(或持久性处理)层提供专门的恢复和错误处理功能,您不想污染业务逻辑。

        4
  •  6
  •   Rogério    16 年前

    根据我以前的经验,我建议使用简单的静态外观,比如 Persistence ,为持久性相关操作提供易于使用的高级API。

    然后,您可以使用静态导入轻松访问那些有用的方法。例如,您可以使用如下代码:

    
        List<Book> cheapBooks = 
            find("select b from Book where b.price < ?", lowPriceForBooks);
        ...
        Book b = new Book(...);
        persist(b);
        ...
        Book existingBook = load(Book.class, bookId);
        remove(existingBook);
        ...
    

        5
  •  6
  •   skaffman    16 年前

    一个词:交易

    假设我必须在一个事务中执行两个数据更新操作。这些操作一起构成一个逻辑工作单元。我的业务逻辑想用这个工作单元来表达自己,它不想用事务边界来麻烦自己。

    所以我写了一把刀。使用Spring事务和hibernate获取以下伪代码:

    编辑删除了HQL,它非常冒犯@Roger,但与要点无关

    @Transactional
    public void doUnitOfWork() {
      // some persistence operation here
      // some other persistence operation here
    }
    

    我的业务逻辑调用doUnitOfWork(),它开始一个事务,执行两个持久性操作,然后提交。它既不知道也不关心事务,也不关心执行了哪些操作。

    此外,如果DAO使用doUnitOfWork()方法实现了一个接口,那么业务逻辑就可以对该接口进行编码,从而更容易进行单元测试。

    一般来说,我 将我的数据访问操作包装在DAO中,并在其周围敲打一个接口。

        6
  •  3
  •   Volksman    15 年前

    现在合适的是存储库和服务的概念:

    存储库: 存储在ORM特定代码(例如Hibernate或JDO)中实现的查询方法集合的类

    通常,您可以创建一个抽象基类存储库,然后提供一个特定于ORM的实现,您可以在其中以特定于ORM的代码实现所有查询方法。这种方法的好处在于,您可以创建一个MockRepository实现,以帮助测试您的应用程序,而无需使用DB。

    服务: 一个类,它存储一组方法,这些方法可以对对象模型(通常是与ORM无关的代码)进行非平凡的更改/添加。

    这有助于保持应用程序在很大程度上独立于ORM—将应用程序移植到另一个ORM实际上只涉及实现新的特定于ORM的存储库类。

        7
  •  3
  •   Jiří Vypědřík    15 年前

        8
  •  3
  •   Kounavi    12 年前

    所有这些对层的介绍都是为了使可维护性变得简单和容易。

    1. 业务层
    2. 表示层

    第一层(数据访问层)的目的是处理数据库逻辑,防止业务层知道任何数据库细节。
    数据访问层使用POJO或EJB(DAO)来实现IoC,POJOEJB使用Hibernate或ORM映射来实际处理数据库层。
    因此,如果您希望您的业务逻辑不应该关心哪个、什么&数据库是如何被使用、访问和更新的,您希望DAO处理这个问题

    本质上,您在数据访问层中实现了一种分层方法,将其功能再次分解为两层,即DAO和Hibernate。

        9
  •  1
  •   Enrique Molinari    10 年前

    如果您使用ORM: 享受他们的透明持久性支持 ! 不要使用DAO包装ORMAPI。正如这里所说的,DAO在ORM之前。 假设您是建模部门和员工。。。一个用例可能是创建一个新部门,创建一个新员工并将该员工添加到该部门。。。你会怎么做?

    //start persistence context
    ...
    Department dept1 = new Department("department1");
    dept1.addEmployee(new Employee("José", 10503f));
    
    em.persist(dept1);
    ...
    //close persistence context
    

    部门、员工和他们之间的关系现在是持久的。

    假设现在您必须将现有员工添加到现有部门。。。你会怎么做?非常简单:

    //start persistence context
    ...
    Department aDepart = hibernateSession.load(Department.class, dId);
    Employee anEmployee = hibernateSession.load(Employee.class, eId);
    
    aDepart.addEmployee(anEmployee);     
    ...
    //close persistence context
    

    由于Hibernate(与其他ORM一样)实现了透明的持久性和可访问持久性,所以非常简单。根本没有DAO。

    只需编写您的域模型,并认为您是在内存中持久化的。有了一个好的映射策略,ORM将透明地将您所做的事情保存在内存中。

    更多示例如下: http://www.copypasteisforword.com/notes/hibernate-transparent-persistence http://www.copypasteisforword.com/notes/hibernate-transparent-persistence-ii

        10
  •  0
  •   andersonbd1    16 年前

    事实上,这比所有这些答案都要简单。这些模式都是关于层的。您不希望循环引用,因为您制作的层只能知道它们上面的内容。您希望您的UICode能够引用任何和所有服务,您的服务代码能够引用任何和所有DAO。

    1. 服务

    从上到下传递POJO。