数据访问对象 (DAO) 和存储库模式有什么区别?我正在使用 Enterprise Java Beans (EJB3)、Hibernate ORM 作为基础架构以及域驱动设计 (DDD) 和测试驱动开发 (TDD) 作为设计技术来开发应用程序。
DAO
是数据持久性的抽象。
Repository
是对象集合的抽象。
DAO
将被视为更接近数据库,通常以表为中心。
Repository
将被视为更接近域,仅处理聚合根。
Repository
可以使用 DAO
来实现,但您不能反其道而行之。
此外,Repository
通常是一个较窄的界面。它应该是一个简单的对象集合,带有 Get(id)
、Find(ISpecification)
、Add(Entity)
。
Update
之类的方法适用于 DAO
,但不适用于 Repository
- 使用 Repository
时,对实体的更改通常由单独的 UnitOfWork 跟踪。
看到称为 Repository
的实现实际上更像是 DAO
似乎很常见,因此我认为它们之间的区别存在一些混淆。
好的,我想我可以更好地解释我在评论中提出的内容:)。因此,基本上,您可以将两者视为相同,尽管 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));
这会给我一种特定语言的所有汽车- 这是正确的做法吗?
CarRepository.findByLanguageId(language.id)
那样编写,您甚至不需要编写代码,您只需使用具有该名称的方法定义接口,Spring Data 会为您构建默认的类实现。很整洁的东西;)
findById
)。你实际上已经完成了。然后 Spring Data 所做的是,它会找到您创建的所有这些接口,这些接口扩展了 Repository 接口并为您创建类。您将永远看不到这些类,也无法创建新实例,但您不需要这样做,因为您可以自动装配接口并让 Spring 定位该存储库对象。
DAO 和存储库模式是实现数据访问层 (DAL) 的方式。所以,让我们首先从 DAL 开始。
访问数据库的面向对象应用程序必须有一些逻辑来处理数据库访问。为了保持代码干净和模块化,建议将数据库访问逻辑隔离到一个单独的模块中。在分层架构中,这个模块是 DAL。
到目前为止,我们还没有讨论任何特定的实现:只是将数据库访问逻辑放在单独的模块中的一般原则。
现在,我们如何实现这个原则?嗯,一种已知的实现方式,特别是使用像 Hibernate 这样的框架,是 DAO 模式。
DAO 模式是一种生成 DAL 的方式,通常每个域实体都有自己的 DAO。例如,User
和 UserDao
、Appointment
和 AppointmentDao
等。带有 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 的目的是隐藏数据访问机制的实现细节。存储库模式有何不同?据我所知,事实并非如此。说存储库与 DAO 不同,因为您正在处理/返回对象集合是不对的; DAO 也可以返回对象的集合。
我读过的关于存储库模式的所有内容似乎都依赖于这种区别:糟糕的 DAO 设计与良好的 DAO 设计(又名存储库设计模式)。
存储库是更抽象的面向领域的术语,它是领域驱动设计的一部分,它是您的领域设计的一部分和一种通用语言,DAO 是数据访问技术的技术抽象,存储库只关心管理现有数据和工厂以创建数据。
检查这些链接:
http://warren.mayocchi.com/2006/07/27/repository-or-dao/ http://fabiomaulo.blogspot.com/2009/09/repository-or-dao-repository.html
DAO 允许以更简单的方式从存储中获取数据,隐藏丑陋的查询。
存储库也处理数据并隐藏查询和所有这些,但是存储库处理业务/域对象。
存储库将使用 DAO 从存储中获取数据并使用该数据恢复业务对象。
例如,DAO 可以包含一些类似的方法 -
public abstract class MangoDAO{
abstract List<Mango>> getAllMangoes();
abstract Mango getMangoByID(long mangoID);
}
存储库可以包含一些类似的方法 -
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帮助我轻松掌握了主要概念。
关键区别在于存储库处理对聚合中聚合根的访问,而 DAO 处理对实体的访问。因此,存储库将聚合根的实际持久性委托给 DAO 是很常见的。此外,由于聚合根必须处理其他实体的访问,因此它可能需要将此访问委托给其他 DAO。
DAO 提供对数据库/数据文件或任何其他持久性机制的抽象,因此可以在不知道其实现细节的情况下操纵持久层。
而在 Repository 类中,可以在单个 Repository 方法中使用多个 DAO 类,以从“应用程序角度”完成操作。因此,与其在域层使用多个 DAO,不如使用存储库来完成它。存储库是一个可能包含一些应用程序逻辑的层,例如:如果数据在内存缓存中可用,则从缓存中获取,否则从网络获取数据并将其存储在内存缓存中以供下次检索。
存储库不过是精心设计的 DAO。
ORM 以表为中心,但不是 DAO。
无需在存储库中使用多个 DAO,因为 DAO 本身可以与 ORM 存储库/实体或任何 DAL 提供程序完全相同,无论汽车在何处以及如何持久化 1 个表、2 个表、n 个表、半个表、一个Web 服务、表格和 Web 服务等。服务使用多个 DAO/存储库。
我自己的 DAO,假设 CarDao 只处理 Car DTO,我的意思是,输入只取 Car DTO,输出只返回 car DTO 或 car DTO 集合。
所以就像 Repository 一样,DAO 实际上是一个 IoC,用于业务逻辑,允许持久性接口不会被持久性策略或遗留问题所吓倒。 DAO 既封装了持久化策略,也提供了与域相关的持久化接口。对于那些不了解定义明确的 DAO 实际上是什么的人来说,存储库只是另一个词。
尝试找出 DAO 或存储库模式是否最适用于以下情况:假设您想为各种类型的数据源(如 RDBMS、LDAP、OODB、XML 存储库和平面文件。
如果有兴趣,也可以参考以下链接:
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
用一个非常简单的一句话来说:显着的区别在于存储库代表集合,而 DAO 更接近数据库,通常更以表为中心。
IRepository
接口。您希望您的存储库在其实现中使用 DAO。请记住,DAO 将是每个表的对象,而 Repository 几乎总是必须使用多个 DAO 来构建单个实体。如果您发现情况并非如此,您的存储库和实体只需要访问一个表,那么您很可能正在构建一个贫血域。