为什么在持久层把一个DAO层(像JDO和Hibernate的)(Why put a DAO laye

2019-08-03 17:34发布

数据访问对象(DAO)是一种常见的设计图案,并通过太阳推荐 但Java的DAO的最早的例子直接与关系数据库交互 - 他们在本质上,这样做的对象关系映射(ORM)。 现在,我看像JDO和Hibernate成熟的ORM框架之上的DAO,我不知道这是否真的是一个好主意。

我正在开发使用JDO作为持久层的web服务,并正在考虑是否要引进的DAO。 与包含地图等对象的特定类打交道时,我可以预见到的问题:

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

JDO是足够聪明的这个“书”和“BOOKDESCRIPTIONS”表之间的映射到外键约束。 它透明加载BookDescription对象(使用延迟加载,我相信),并且将它们保存在Book对象持久化。

如果我是引入“数据访问层”,写像BookDao一类,并在此封装所有的JDO的代码,那么就不会这样JDO的孩子的透明负载对象被绕过数据访问层? 为了保持一致性,应该不是所有的对象BookDescription被加载,并通过一些BookDescriptionDao对象(或BookDao.loadDescription方法)持续? 然而,在这种方式重构将使操纵模型必要的复杂。

所以我的问题是,什么是错调用JDO(或休眠状态,或任何ORM你喜欢)直接在业务层? 它的语法已经相当简洁,它是数据存储无关。 什么是优势,如果有的话,在数据访问对象封装呢?

Answer 1:

这取决于你的层的目标是什么。 你把一个抽象了另一组以提供一组不同的语义。 一般来说进一步层有简化出头如未来maintennance的发展。 但是,他们可以有其他用途。

例如一个DAO(或持久性处理)层上的ORM密码供应专业恢复和错误处理功能,你不想污染的业务逻辑。



Answer 2:

你让一些要点。 但我仍然使用了DAO层,这里的原因:

  1. 数据库访问是到远程系统调用 。 在所有这些情况下(也Web服务,AJAX等),互动的粒度必须足够大。 许多微小的通话将杀死性能。 这种性能的必要性需要系统的往往不同的观点,或层(这里,道层)。

  2. 有时候,你的持久操作只加载/保存/删除的对象。 一个独特道(或超;考虑仿制药)可以负责这一点,所以你不必一次又一次地编写这些方法。
    但往往,你也有特定的需求,如跑步是不会自动ORM创建的具体要求 。 在那里,你的代码与特定的道法的具体需求(重用往往是可能的)。
    具有在同一层常规和特殊的需要允许重用(例如,拦截可以确保在需要时数据库连接是打开/ COMMITED)。



Answer 3:

DAO已经失去了一段时间的意义。

在J2EE天,当它成为一个流行的模式,一个DAO是一个类,你可以同时满足多个数据源 - 由一个供应商数据库,由另一个数据库,文件 - 并提供一个单一的地方包裹查询通信数据。

有大量的范围进行再利用,因此对于特定实体的DAO对象很可能延长其容纳在可重复使用的东西,这本身实现的DAO接口的抽象DAO。

后J2EE / EJB中,DataMapper的和DataSource模式(或简单的系统,ActiveRecord的)走红执行相同的作用。 然而,DAO成为参与任何持久化对象流行语。

Nowdays,术语“DAO”已经黯然成为“一类的使我与我的数据库进行通信”的代名词。

随着ORM / JPA,多一个真正的,J2EE时代DAO的理由提供开箱即用。

在后面的数据源模式的情况下,JPA的EntityManager的是类似于数据源,但通常经由PersistenceUnit XML定义中提供并经由IoC的实例化。

现在可以恰好一次使用存储库的图案来提供曾经住在DAO或映射器CRUD方法。 有没有必要AbstractDao的公司 - 的ORM产品是足够聪明的接受对象(),并知道它是坚持它。



Answer 4:

当使用像JDO或JPA ORM工具,DAO的是一个反模式。 在这种情况下,建立一个“数据访问层”是完全没有必要,只会增加额外的代码和复杂的代码库,使其难以开发和维护。

根据我以前的经验,我会建议使用一个简单的静态的门面,说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);
    ...

上面的代码是作为容易和简单越好,并且可以很容易地进行单元测试。



Answer 5:

一个字:交易

就拿情况下,我必须在一个事务中执行两个数据更新操作。 这些操作共同构成一个逻辑工作单元。 我的商业逻辑所要表达自己的工作单元而言,它并不希望与事务边界打扰自己。

所以我写了一个DAO。 使用Spring事务和Hibernate把这个伪代码:

编辑删除HQL这是得罪@Roger这么多,但是这是不相关的点

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

我的商业逻辑调用doUnitOfWork(),它开始一个事务,执行两种持久化操作,然后提交。 它不知道也不关心有关交易,或进行什么样的操作。

此外,如果DAO实现与doUnitOfWork()方法的接口,则业务逻辑可以编码到接口,从而更容易进行单元测试。

一般来说,我一直包在我的DAO数据访问操作,并捶围绕它的接口。



Answer 6:

我相信大多数的DAO是由人来添加histerical(历史])的原因。 你是正确的,他们intially意味着作为在预ORM天执行CRUD操作所需的SQL胶水方便封装。 如今,随着透明的持久性,它们的作用是现在基本上是多余的。

什么是合适的,现在是库和服务的概念:

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

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

服务:存储的可编排非平凡改变/添加到对象模型方法的集合的类(通常ORM无关的代码)。

这有助于保持你的应用程序主要是ORM独立 - 端口应用到另一个ORM实际上只涉及到一个新的ORM特定仓储类(ES)的实施。



Answer 7:

我想,该图案“每个实体DAO类”是一个ORM管理数据层绝对是多余的。 相反,DAO层应当由一组中的一个通用型,关于任意的实体类操作CRUD方法集和大量的该对数据执行更复杂的操作方法。 如果这项功能是足够大,那么DAO层应分为基于域标准的多个类,是什么使这种方法更类似于面向服务的体系结构。



Answer 8:

这一切的介绍层的目的是使维护简单方便。

  1. 数据访问层
  2. 业务层
  3. 表示层

在第一层(数据访问层)的目的是处理与数据库的逻辑和防止业务层从知道任何细节DB。
数据访问层使用POJO或EJB(DAO)来实现的IoC和POJOEJBs使用Hibernate或者ORM映射到实际与数据库层处理。
所以,如果你希望你的业务逻辑不应该关心它,你想DAO照顾这个东西和如何数据库正在被使用,访问和更新,
DAO可以支持改变不同的表通过使数休眠的呼叫,以支持操作的逻辑。
从本质上讲,你是在两层又名DAO和Hibernate再次打破其功能实现在数据访问层分层的方法。



Answer 9:

如果您使用的ORM: 享受透明持久性的支持 ! 不要使用DAO的包裹ORM的API。 由于这是很好这里说,DAO的是奥姆斯之前。 奥姆斯已经介绍的概念从面向对象数据库,就像可达透明的持久性和持久性。 你要利用这一点,因为它会让你的生活更轻松,你的代码美丽。 假设你正在建模部门和员工......一个用例可能是创建一个新的部门,建立一个新员工,增加员工到部门......你会做什么?

//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



Answer 10:

它实际上必须比所有这些答案简单做出来是。 这些模式都是关于层。 你不想循环引用,你应当层,可以只了解事情在他们之上。 您希望您的UICODE能够引用任何和所有的服务,您的服务代码能够引用任何和所有的DAO。

  1. DAO
  2. Service
  3. UICode

与POJO的自上而下传递给底部。



文章来源: Why put a DAO layer over a persistence layer (like JDO or Hibernate)