DAO和存储库模式之间有什么区别?


Answers:


471

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

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

Repository可以使用来实现DAO,但您不会做相反的事情。

同样,a Repository通常是较窄的接口。它应该是简单对象的集合,有Get(id)Find(ISpecification)Add(Entity)

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

看到称为a的实现确实看起来Repository更像a DAO,这确实很常见,因此我认为它们之间的差异有些混乱。


26
好吧,您不希望您的DAO类从字面上实现您的IRepository接口。您希望您的存储库在其实现中使用DAO。请记住,DAO将是每个表的对象,而存储库几乎总是必须使用多个DAO来构建单个实体。如果您发现情况并非如此,则您的存储库和实体仅需要访问一个表,那么您很可能正在构建贫血域。
2011年

29
我已经在.NET世界中注意到,术语“存储库”实际上是指DAO;“ DAO”更多是Java术语。
韦恩·莫利纳

14
@Thurein DAO-s不是按表的,该模式只是抽象对数据的访问-您可以按自己的喜好实现(按表,按组或按模型)。推荐的方法是始终根据域模型来塑造DAO,而不要考虑底层的持久性,因为这样可以更容易/更清晰地使用它,并在持久性方面给您更多的灵活性(例如,假设您需要一个将您的数据存储在XML文件中或从消息队列而不是从数据库中获取数据的DAO ...)。
Stef

21
@Stef,我不同意。DAO 通过其定义(数据访问对象)返回数据。根据其定义,存储库返回域对象。应该有理由认为,存储库将使用DAO,而不是使用其他方法,因为在OOP中,我们是用一个或多个数据对象组成域对象,而不是使用其他方法。
Mihai Danila

6
为什么在DAO为“读写”的情况下,存储库是“只读”概念的?
丹尼斯

120

好的,我认为我可以更好地解释我在评论中提出的内容:)。因此,尽管DAO比存储库更灵活,但基本上可以将两者视为相同。如果要同时使用两者,则可以在DAO-s中使用存储库。我将在下面解释它们中的每一个:

储存库:

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

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

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

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

例如,您可以轻松地使用UserDao公开诸如

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

所有这些都与用户(和安全性)相关,并且可以在同一DAO下指定。对于存储库,情况并非如此。

最后

请注意,这两种模式实际上含义相同(它们存储数据并抽象化对数据的访问,并且都表示为更接近域模型,并且几乎不包含任何数据库引用),但是它们的使用方式可能略有不同,因为DAO是稍微灵活/泛型,而存储库则更具体和仅对类型进行限制。


如果我做对了(例如,我有类似这样的东西CarDescription,例如language_id作为外键),那么检索到我应该做这样的事情:CarRepository.getAll(new Criteria(carOwner.id, language.id));这将为我提供使用特定语言的所有语言的汽车-就是这样做的正确方法?
displayname

@StefanFalk,看看Spring Data,它使您可以进行比这更好的调用。例如,可以这样写,CarRepository.findByLanguageId(language.id)而您甚至不需要编写代码,只需使用具有该名称的方法定义接口,Spring Data就会为您构建默认的类实现。漂亮的东西;)
Stef

2
Spring Data的优点在于,您实际上不必编写查询,只需创建一个接口(如示例中的TodoRepository,该接口具有方法findById)。您实际上已经完成了。然后,Spring Data要做的是,找到您创建的所有这些接口,这些接口扩展了Repository接口并为您创建类。您将永远不会看到那些类,也将无法创建新实例,但是您无需这样做,因为您可以自动装配接口并让Spring查找该存储库对象。
Stef

1
最后,您不必使用Spring Data,可以采用旧的编写查询方法的方式(使用Criteria API等),但是您只会使生活变得更加复杂...您可能会说这样您将具有更大的灵活性,但这不是真的,就好像您真的想对查询发疯一样,Spring Data允许您这样做的两种方式:@Query注释,或者如果不起作用,则创建自定义存储库,它是一个扩展,可以为您提供与从头开始编写自己的实现相同的功能。
Stef

2
“聚合根”是一个经常与存储库模式相关的术语。我不知道如何在存储库定义中使用它。
基督教Strempfer

90

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()。相反,它意味着它应该支持诸如添加,删除,包含等操作。这是存储库模式的本质。

实际上,例如在使用休眠的情况下,可以通过DAO实现存储库模式。那就是DAL的实例可以同时是DAO模式和存储库模式的实例。

存储库模式不一定是在DAO之上构建的(有些人可能会建议)。如果DAO设计为具有支持上述操作的接口,则它是Repository模式的一个实例。想想看,如果DAO已经提供了类似集合的操作集,那么在它之上需要一个额外的层是什么呢?


5
“如果DAO已经提供了类似集合的一组操作,那么在它之上需要一个额外的层是什么呢?” 假设您正在为一家宠物店建模,并且有一个表“ PetType”,其中包含不同动物及其属性(名称:“猫”,类型:“哺乳动物”等),由您所养宠物的表“宠物”引用在商店中(名称:“ Katniss”,品种:“ Calico”等)。如果你想在数据库中没有添加类型的动物,你可以使用一个存储库组的两个独立的DAO调用(一个创建PetType和其他的宠物)的一种方法,避免DAO中耦合
马特

1
先生,很棒的解释!
Paul-Sebastian Manole

74

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

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

我所阅读的有关存储库模式的所有内容似乎都取决于这种区别:不良的DAO设计与良好的DAO设计(又称存储库设计模式)。


5
是的,完全同意,它们本质上是相同的。DAO听起来与DB有关,但事实并非如此。与存储库相同,它只是用于隐藏数据位置和方式的抽象。
Stef

+1对于此声明。坦白地说,这看起来像是语义上的区别,而不是技术上的区别。短语“数据访问对象”根本没有引用“数据库”。
Sudhakar Chavali

1
比较存储库和集合的重点不是它们正在处理/返回对象的集合,而是存储库的行为就好像它们集合本身一样。例如,在Java中,这意味着存储库没有更新方法,因为在修改集合中的对象时,它会自动更新(因为Java集合仅存储对对象的引用)。
ChristophBöhme


6

关键区别在于,存储库处理对聚合中的聚合根的访问,而DAO处理对实体的访问。因此,存储库通常将聚合根的实际持久性委派给DAO。此外,由于聚合根必须处理其他实体的访问,因此可能需要将此访问委派给其他DAO。


5

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

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


3

存储库不过是精心设计的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与数据库接口并委托实体操作。
保罗·塞巴斯蒂安·曼诺

3
同意@brokenthorn。在他的评论中,最关键的一点是“存储库是最高的抽象”,当您要保护域代码不受基础数据库技术的影响时,这种抽象就成为必需。ORM /适配器/数据库驱动程序概念倾向于泄漏到DAO中。如果您的应用程序支持多种数据库技术,或者希望您的应用程序不被锁定到数据库,则直接从域模型中使用DAO是不可行的。
Subhash Bhushan

2


0

在spring框架中,有一个称为存储库的注释,在此注释的描述中,有关于存储库的有用信息,我认为这对本次讨论很有用。

指示带注释的类是“存储库”,最初由Domain-Driven Design(Evans,2003)定义为“一种封装存储,检索和搜索行为的机制,该机制模仿对象的集合”。

实现诸如“数据访问对象”之类的传统Java EE模式的团队也可以将这种构造型应用于DAO类,尽管在这样做之前应注意理解数据访问对象和DDD样式存储库之间的区别。此注释是通用的刻板印象,各个团队可以缩小其语义并适当使用。

与PersistenceExceptionTranslationPostProcessor结合使用时,这样注释的类可以进行Spring DataAccessException转换。出于工具,方面等目的,还注释了带注释的类在整个应用程序体系结构中的作用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.