DAO 和存储库模式有啥区别?

Posted

技术标签:

【中文标题】DAO 和存储库模式有啥区别?【英文标题】:What is the difference between DAO and Repository patterns?DAO 和存储库模式有什么区别? 【发布时间】:2016-04-07 11:40:52 【问题描述】:

数据访问对象 (DAO) 和存储库模式有什么区别?我正在使用 Enterprise Java Beans (EJB3)、Hibernate ORM 作为基础架构以及域驱动设计 (DDD) 和测试驱动开发 (TDD) 作为设计技术来开发应用程序。

【问题讨论】:

【参考方案1】:

DAO数据持久性的抽象。Repository对象集合的抽象。

DAO 将被认为更接近数据库,通常以表为中心。Repository 将被认为更接近域,仅处理聚合根。

Repository 可以使用DAO 来实现,但你不会反其道而行之。

另外,Repository 通常是一个更窄的接口。它应该是一个简单的对象集合,带有Get(id)Find(ISpecification)Add(Entity)

Update 之类的方法适用于 DAO,但不适用于 Repository - 使用 Repository 时,实体的更改通常由单独的 UnitOfWork 跟踪。

看到称为Repository 的实现实际上更像DAO 似乎很常见,因此我认为它们之间的区别存在一些混淆。

【讨论】:

好吧,你不希望你的 DAO 类真正实现你的IRepository 接口。您希望您的存储库在其实现中使用 DAO。请记住,DAO 将是每个表的对象,而 Repository 几乎总是必须使用多个 DAO 来构建单个实体。如果您发现情况并非如此,您的 Repository 和 Entity 只需要访问一个表,那么您很可能正在构建一个贫血域。 我注意到在 .NET 世界中,术语“存储库”专门用于指代本质上是 DAO 的东西; “DAO”更像是一个 Java 术语。 @Thurein DAO-s 不是每个表,该模式只是抽象对您的数据的访问 - 您可以根据自己的喜好实现它(每个表,或每个组或模型)。推荐的方法是始终根据您的域模型来塑造您的 DAO,而不是将底层持久性考虑在内,因为这使得它更容易/更清晰地使用,并为您提供了更多的灵活性来持久化它(例如,假设您需要将数据存储在 XML 文件中或从消息队列而不是从数据库中获取数据的 DAO ...)。 @Stef 我不同意。 DAO 根据其定义(data 访问对象)返回 data。根据其定义,存储库返回域对象。存储库将使用 DAO 而不是相反的方式应该是有道理的,因为在 OOP 中,我们由一个或多个数据对象组成域对象,而不是相反。 为什么存储库是“只读”概念,而 DAO 是“读写”?【参考方案2】:

Repository 是更抽象的面向领域的术语,是 Domain Driven Design 的一部分,它是您的领域设计和通用语言的一部分,DAO 是数据访问技术的技术抽象,repository 只关注管理现有数据和工厂用于创建数据。

检查这些链接:

http://warren.mayocchi.com/2006/07/27/repository-or-dao/ http://fabiomaulo.blogspot.com/2009/09/repository-or-dao-repository.html

【讨论】:

【参考方案3】:

尝试找出 DAO 或 Repository 模式是否最适用于以下情况: 想象一下,您想为各种类型的数据源(例如 RDBMS、LDAP、OODB、XML 存储库和平面文件)提供一个统一的数据访问 API 以实现持久性机制。

如果有兴趣,也可以参考以下链接:

http://www.codeinsanity.com/2008/08/repository-pattern.html

http://blog.fedecarg.com/2009/03/15/domain-driven-design-the-repository/

http://devlicio.us/blogs/casey/archive/2009/02/20/ddd-the-repository-pattern.aspx

http://en.wikipedia.org/wiki/Domain-driven_design

http://msdn.microsoft.com/en-us/magazine/dd419654.aspx

【讨论】:

【参考方案4】:

坦率地说,这看起来像是语义上的区别,而不是技术上的区别。短语数据访问对象根本不指“数据库”。而且,尽管您可以将其设计为以数据库为中心,但我认为大多数人会认为这样做是设计缺陷。

DAO 的目的是隐藏数据访问机制的实现细节。存储库模式有何不同?据我所知,事实并非如此。说存储库与 DAO不同,因为您正在处理/返回对象集合是不对的; DAO 还可以返回对象的集合。

我所读到的关于存储库模式的所有内容似乎都依赖于这种区别:糟糕的 DAO 设计与良好的 DAO 设计(又名存储库设计模式)。

【讨论】:

是的,完全同意,它们本质上是一样的。 DAO 听起来更与 DB 相关,但事实并非如此。与 Repository 相同,它只是一个抽象,用于隐藏数据的位置和方式。 +1 对于此声明。坦率地说,这看起来像是语义上的区别,而不是技术上的区别。短语数据访问对象根本不指“数据库”。 比较存储库和集合的要点不是它们正在处理/返回对象的集合,而是存储库的行为就像它们本身集合一样。例如,在 Java 中,这意味着 Repository 没有更新方法,因为当您修改集合中的对象时,它会自动更新(因为 Java 集合只存储对对象的引用)。【参考方案5】:

主要区别在于存储库处理对聚合中聚合根的访问,而 DAO 处理对实体的访问。因此,存储库将聚合根的实际持久性委托给 DAO 是很常见的。此外,由于聚合根必须处理其他实体的访问权限,因此它可能需要将此访问权限委托给其他 DAO。

【讨论】:

【参考方案6】:

DAO 和存储库模式是实现数据访问层 (DAL) 的方式。所以,让我们先从 DAL 开始。

访问数据库的面向对象应用程序必须有一些逻辑来处理数据库访问。为了保持代码干净和模块化,建议将数据库访问逻辑隔离到一个单独的模块中。在分层架构中,这个模块是 DAL。

到目前为止,我们还没有讨论任何特定的实现:只是将数据库访问逻辑放在单独的模块中的一般原则。

现在,我们如何实现这个原则?嗯,一种已知的实现方式,特别是使用像 Hibernate 这样的框架,是 DAO 模式。

DAO 模式是一种生成 DAL 的方式,通常每个域实体都有自己的 DAO。例如UserUserDaoAppointmentAppointmentDao等。带有Hibernate的DAO示例:http://gochev.blogspot.ca/2009/08/hibernate-generic-dao.html。

那么什么是存储库模式?与 DAO 一样,存储库模式也是实现 DAL 的一种方式。存储库模式的要点是,从客户端/用户的角度来看,它应该看起来或行为像一个集合。表现得像一个集合的意思并不是它必须像Collection collection = new SomeCollection() 那样实例化。相反,它意味着它应该支持诸如添加、删除、包含等操作。这就是存储库模式的精髓。

在实践中,例如在使用 Hibernate 的情况下,Repository 模式是通过 DAO 实现的。即 DAL 的一个实例可以同时是 DAO 模式和存储库模式的一个实例。

存储库模式不一定是建立在 DAO 之上的东西(正如一些人可能建议的那样)。如果 DAO 设计有支持上述操作的接口,那么它就是 Repository 模式的一个实例。想一想,如果 DAO 已经提供了一组类似集合的操作,那么在它之上还需要一个额外的层吗?

【讨论】:

“如果 DAO 已经提供了一组类似集合的操作,那么在它之上还需要额外的层吗?”假设您正在为一家宠物店建模,并且您有一个表“PetType”,其中包含不同的动物及其属性(名称:“Cat”,类型:“哺乳动物”等),由您的具体宠物的表“Pet”引用店内有(名称:“Katniss”,品种:“Calico”等)。如果您想添加数据库中尚未存在的动物类型,您可以使用存储库将两个单独的 DAO 调用(一个用于创建 PetType,另一个用于 Pet)在一种方法中进行分组,避免 DAO 中的耦合跨度> 精湛的解释,先生!【参考方案7】:

好的,我想我可以更好地解释我在 cmets 中放入的内容 :)。 因此,基本上,您可以将两者视为相同,尽管 DAO 是一种比 Repository 更灵活的模式。如果你想同时使用两者,你​​可以在你的 DAO-s 中使用 Repository。我将在下面逐一解释:

存储库:

它是特定类型对象的存储库 - 它允许您搜索特定类型的对象并存储它们。通常它只会处理一种类型的对象。例如。 AppleRepository 将允许您执行 AppleRepository.findAll(criteria)AppleRepository.save(juicyApple)。 请注意,存储库使用的是域模型术语(不是数据库术语 - 与数据如何在任何地方持久保存无关)。

存储库很可能会将所有数据存储在同一个表中,而该模式不需要这样做。虽然它只处理一种类型的数据,但它在逻辑上连接到一个主表(如果用于 DB 持久性)。

DAO - 数据访问对象(换句话说 - 用于访问数据的对象)

DAO 是一个为您定位数据的类(它主要是一个查找器,但通常也用于存储数据)。该模式不限制您存储相同类型的数据,因此您可以轻松拥有一个定位/存储相关对象的 DAO。

例如您可以轻松地拥有 UserDao 来公开方法,例如

Collection<Permission> findPermissionsForUser(String userId)
User findUser(String userId)
Collection<User> findUsersForPermission(Permission permission)

所有这些都与用户(和安全)相关,可以在同一个 DAO 下指定。存储库不是这种情况。

终于

请注意,这两种模式的真正含义是相同的(它们存储数据并抽象出对它的访问,它们都更接近域模型并且几乎不包含任何数据库引用),但它们的使用方式可能略有不同, DAO 更加灵活/通用,而 Repository 更加具体且仅限于一种类型。

【讨论】:

如果我做对了,例如我有类似CarDescription 的东西,例如language_id 作为外键 - 然后检索我应该做这样的事情:CarRepository.getAll(new Criteria(carOwner.id, language.id)); 这将为我提供特定语言的所有汽车 - 这是正确的方法吗? @StefanFalk,看看 Spring Data,它可以让你做比这更好的调用。例如可以像CarRepository.findByLanguageId(language.id) 这样写,你甚至不需要编写代码,你只需使用具有该名称的方法定义接口,Spring Data 会为你构建默认的类实现。非常整洁的东西;) Spring Data 的美妙之处在于您实际上不必编写查询,您只需创建一个接口(如示例中的 TodoRepository,它具有方法 findById)。你实际上已经完成了。然后 Spring Data 所做的是,它会找到您创建的所有这些接口,这些接口扩展了 Repository 接口并为您创建类。您永远不会看到这些类,也无法创建新实例,但您不需要这样做,因为您可以自动装配接口并让 Spring 定位该存储库对象。 最后,您不必使用 Spring Data,您可以自己编写查询方法的旧方法(使用 Criteria API 等),但您只会让您的生活多一点复杂......你可能会说你会有更多的灵活性,但这不是真的,因为如果你真的想对你的查询发疯,Spring Data 允许你这样做:@Query 注释,或者如果这不起作用,您可以创建自定义存储库,它是一个扩展,为您提供与从头开始编写自己的实现相同的功能。 “聚合根”是一个经常与存储库模式相关的术语。我不知道您将如何将它与您的存储库定义一起使用。【参考方案8】:

存储库不过是精心设计的 DAO。

ORM 以表为中心,但不是 DAO。

无需在存储库中使用多个 DAO,因为 DAO 本身可以对 ORM 存储库/实体或任何 DAL 提供程序执行完全相同的操作,无论汽车在何处以及如何持久化 1 个表、2 个表、n 个表、半个表表、Web 服务、表和 Web 服务等。 服务使用多个 DAO/存储库。

我自己的 DAO,假设 CarDao 只处理 Car DTO,我的意思是,输入只接受 Car DTO,输出只返回 car DTO 或 car DTO 集合。

所以就像存储库一样,DAO 实际上是一个 IoC,用于业务逻辑,允许持久性接口不会被持久性策略或遗留问题所吓倒。 DAO 既封装了持久化策略,也提供了与域相关的持久化接口。 对于那些不了解定义明确的 DAO 到底是什么的人来说,存储库只是另一个词。

【讨论】:

首先是“ORM 存储库/实体”?你的意思是 ORM 实体。没有像 ORM 存储库这样的东西。其次,ORM 通常只处理实体,即。领域模型。 DAO 直接处理表并抽象数据访问。他们也返回实体。存储库是最高的抽象,提供了一个集合接口来获取实体。 DAO 可以是一个存储库,即。抽象实际的存储引擎,为其提供接口并提供(缓存)实体的集合视图。 DAO 可以使用 ORM 与数据库交互并委托实体操作。 同意@brokenthorn。他的评论中最关键的一点是“存储库是最高的抽象”,当您想要保护您的域代码免受底层数据库技术的影响时,这种抽象就成为必需品。 ORM/Adapter/DB Driver 的概念往往会泄漏到 DAO 中。如果您的应用程序支持多种数据库技术,或者您希望您的应用程序不被锁定到数据库,那么直接从域模型中使用 DAO 是不行的。【参考方案9】:

用一个非常简单的句子:显着的区别是 存储库代表集合,而 DAO 更接近数据库,通常更 以表为中心。

【讨论】:

【参考方案10】:

DAO 提供对数据库/数据文件或任何其他持久性机制的抽象,因此可以在不知道其实现细节的情况下操纵持久层。

而在 Repository 类中,多个 DAO 类可以在单个 Repository 方法中使用,以从“应用程序角度”完成操作。因此,与其在域层使用多个 DAO,不如使用存储库来完成它。 Repository 是一个可能包含一些应用程序逻辑的层,例如:如果数据在内存缓存中可用,则从缓存中获取,否则从网络获取数据并将其存储在内存缓存中以备下次使用检索。

【讨论】:

【参考方案11】:

在spring框架中,有一个注解叫做repository,在这个注解的描述中,有关于repository的有用信息,我觉得对这个讨论很有用。

表明一个带注释的类是一个“Repository”,最初 由领域驱动设计 (Evans, 2003) 定义为“一种机制 封装存储、检索和搜索行为,模拟一个 对象集合”。

实现传统 Java EE 模式(例如“数据访问”)的团队 Object" 也可以将此构造型应用于 DAO 类,但要小心 应该理解数据访问之间的区别 这样做之前的对象和 DDD 样式的存储库。这个注解是 通用的刻板印象和个别团队可能会缩小他们的 语义并酌情使用。

这样注释的类符合 Spring DataAccessException 的条件 与 a 结合使用时的翻译 PersistenceExceptionTranslationPostProcessor。带注释的类是 还阐明了其在整个应用程序架构中的作用 用于工具、方面等的目的。

【讨论】:

【参考方案12】:

DAO 允许以更简单的方式从存储中获取数据,隐藏丑陋的查询。

Repository 也处理数据并隐藏查询等,但存储库处理业务/域对象

存储库将使用 DAO 从存储中获取数据并使用该数据恢复 业务对象

例如,一个 DAO 可以包含一些类似的方法 -

 public abstract class MangoDAO
   abstract List<Mango>> getAllMangoes();
   abstract Mango getMangoByID(long mangoID);

Repository 可以包含一些类似的方法 -

   public abstract class MangoRepository
       MangoDao mangoDao = new MangDao;

       Mango getExportQualityMango()

       for(Mango mango:mangoDao.getAllMangoes())
        /*Here some business logics are being applied.*/
        if(mango.isSkinFresh()&&mangoIsLarge()
           mango.setDetails("It is an export quality mango");
            return mango;
           
       
    

tutorial 这个tutorial 帮助我轻松掌握了主要概念。

【讨论】:

以上是关于DAO 和存储库模式有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

DAO 和 Data Mapper 有啥区别

spring-data-jpa 存储库模式与 Querydsl 查询模式有啥区别?

数据访问层和数据访问对象有啥区别?

映像和存储库有啥区别?

POJO和DAO有啥区别

装饰器、包装器和适配器模式之间有啥区别?