【Spring】DAO 和 Repository 的区别
DAO 和 Repository 的区别
- 1.概述
- 2.DAO 模式
- 2.1 User
- 2.2 UserDao
- 2.3 UserDaoImpl
- 3.Repository 模式
- 3.1 UserRepository
- 3.2 UserRepositoryImpl
- 4.具有多个 DAO 的 Repository 模式
- 4.1 Tweet
- 4.2 TweetDao 和 TweetDaoImpl
- 4.3 增强 User 域
- 4.4 UserRepositoryImpl
- 5.比较两种模式
- 6.结论
1.概述
通常,Repository 和 DAO 的实现被认为是可互换的,特别是在 以数据为中心 的应用程序中。这造成了对它们差异的混淆。
在本文中,我们将讨论 DAO 和 Repository 模式之间的差异。

2.DAO 模式
数据访问对象(Data Access Object,DAO)模式是数据持久性的抽象,被认为更接近于底层存储,而底层存储通常以表为中心。因此,在许多情况下,我们的 DAO 与数据库表匹配,允许更直接的方式从存储中 发送/检索 数据,从而隐藏丑陋的查询。
让我们来看看 DAO 模式的简单实现。
2.1 User
首先,让我们创建一个基本的 User 域类。
public class User {private Long id;private String userName;private String firstName;private String email;// getters and setters
}
2.2 UserDao
然后,我们将创建 UserDao 接口,该接口为 User 域提供简单的 CRUD 操作。
public interface UserDao {void create(User user);User read(Long id);void update(User user);void delete(String userName);
}
2.3 UserDaoImpl
最后,我们将创建实现 UserDao 接口的 UserDaoImpl 子类。
public class UserDaoImpl implements UserDao {private final EntityManager entityManager;@Overridepublic void create(User user) {entityManager.persist(user);}@Overridepublic User read(long id) {return entityManager.find(User.class, id);}// ...
}
在这里,为了简单起见,我们使用 JPA EntityManager 接口与底层存储交互,并为用户域提供数据访问机制。
3.Repository 模式
根据 Eric Evans 的《领域驱动设计》:Repository 是一种封装存储、检索和搜索行为的机制,它模拟对象的集合。
同样,根据《企业应用架构模式》,它使用类似于集合的接口访问领域对象,在 领域层 和 数据映射层 之间进行调解。换句话说,Repository 也处理数据并隐藏查询,与 DAO 类似。不过,它位于更高层次,更接近应用程序的业务逻辑。
因此,Repository 可以使用 DAO 从数据库获取数据并填充域对象。或者,它可以准备域对象中的数据,并使用 DAO 将其发送到存储系统以实现持久性。
让我们看看 User 域的 Repository 模式的简单实现。
3.1 UserRepository
首先,让我们创建用户存储库接口。
public interface UserRepository {User get(Long id);void add(User user);void update(User user);void remove(User user);
}
在这里,我们添加了一些常用方法,如 get、add、update 和 remove,以处理对象集合。
3.2 UserRepositoryImpl
然后,我们将创建 UserRepositoryImpl 类,提供 UserRepository 接口的实现。
public class UserRepositoryImpl implements UserRepository {private UserDaoImpl userDaoImpl;@Overridepublic User get(Long id) {User user = userDaoImpl.read(id);return user;}@Overridepublic void add(User user) {userDaoImpl.create(user);}// ...
}
在这里,我们使用 UserDaoImpl 从数据库中 发送/检索 数据。
到目前为止,我们可以说 DAO 和 Repository 的实现看起来非常相似,因为 User 类是一个 Anemic Domain。而且,Repository 只是数据访问层(DAO)的另一层。
🚀 只包含数据,不包含业务逻辑的类,就叫作 贫血模型(Anemic Domain Model)。贫血模型将数据与操作分离,破坏了面向对象的封装特性,是一种典型的面向过程的编程风格。
但是,DAO 似乎是 访问数据 的完美候选者,Repository 是 实现业务用例 的理想方式。
4.具有多个 DAO 的 Repository 模式
为了清楚地理解最后一句话,让我们加强 User 域来处理业务用例。
想象一下,我们想通过聚合一个用户的 Twitter 推文、Facebook 帖子等,为他准备一份社交媒体档案。
4.1 Tweet
首先,我们将创建具有一些保存推文信息的属性的 Tweet 类:
public class Tweet {private String email;private String tweetText; private Date dateCreated;// getters and setters
}
4.2 TweetDao 和 TweetDaoImpl
然后,与 UserDao 类似,我们将创建允许获取推文的 TweetDao 界面:
public interface TweetDao {List<Tweet> fetchTweets(String email);
}
同样,我们将创建 TweetDaoImpl 类,该类提供 fetchTweets 方法的实现:
public class TweetDaoImpl implements TweetDao {@Overridepublic List<Tweet> fetchTweets(String email) {List<Tweet> tweets = new ArrayList<Tweet>();//call Twitter API and prepare Tweet objectreturn tweets;}
}
在这里,我们将调用 Twitter API,使用用户的电子邮件获取其所有推文。
因此,在这种情况下,DAO 提供了一种使用第三方 API 的数据访问机制。
4.3 增强 User 域
最后,让我们创建 User 类的 UserSocialMedia 子类,以保留 Tweet 对象的列表。
public class UserSocialMedia extends User {private List<Tweet> tweets;// getters and setters
}
在这里,我们的 UserSocialMedia 是一个复杂的域,其中包含 User 域的属性。
4.4 UserRepositoryImpl
现在,我们将升级我们的 UserRepositoryImpl 类,以提供 User 域对象以及推文列表。
public class UserRepositoryImpl implements UserRepository {private UserDaoImpl userDaoImpl;private TweetDaoImpl tweetDaoImpl;@Overridepublic User get(Long id) {UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);List<Tweet> tweets = tweetDaoImpl.fetchTweets(user.getEmail());user.setTweets(tweets);return user;}
}
在这里,UserRepositoryImpl 使用 UserDaoImpl 提取用户数据,并使用 TweetDaoImpl 提取用户的推文。
然后,它聚合两组信息,并提供 UserSocialMedia 类的域对象,该对象对于我们的业务用例非常方便。因此,存储库依赖于 DAO 来访问来自各种源的数据。
同样,我们可以增强我们的用户域以保留 Facebook 帖子列表。
5.比较两种模式
现在我们已经看到了 DAO 和 Repository 模式的细微差别,让我们总结一下它们的区别:
- DAO 是数据持久性的抽象。但是,Repository 是对象集合的抽象。
- DAO 是一个较 低 级别的概念,更接近 存储系统。但是,Repository 是一个更 高 层次的概念,更接近 域对象。
- DAO 作为 数据映射/访问层 工作,隐藏丑陋的查询。但是,Repository 是 域 和 数据访问层 之间的一层,隐藏了整理数据和准备域对象的复杂性。
- DAO 不能使用 Repository 实现。但是,Repository 可以使用 DAO 来访问底层存储。
而且,如果我们有一个贫血域,Repository 将只是一个 DAO。
此外,Repository 模式鼓励域驱动的设计,也为非技术团队成员提供了对数据结构的轻松理解。
- 职责不同:Repository 负责数据访问的逻辑管理,封装与数据库的交互操作,包括数据的增删改查等。Repository 的设计目标是提供一个统一的接口,将数据访问逻辑与业务逻辑分离,使得业务逻辑更加清晰和可维护。DAO 更关注于数据访问的实现细节,与具体的数据库交互,实现数据的存储和检索等功能。
- 抽象层次不同:Repository 提供一种更加抽象的数据访问方式,将数据访问的逻辑从业务逻辑中分离出来,使得业务逻辑与数据访问无关,降低代码耦合度,提高可维护性和可扩展性。Repository 定义一组通用的接口和方法,供业务模块调用。DAO 更接近于具体的数据访问实现,直接与数据库交互,实现数据的存储和检索等功能。DAO 的设计目标是提供一组具体的数据访问方法,以满足业务模块的具体需求。
6.结论
在本文中,我们探讨了 DAO 和 Repository 模式之间的差异。
首先,我们研究了 DAO 模式的基本实现。然后,我们看到了使用 Repository 模式的类似实现。
最后,我们研究了一个利用多个 DAO 的 Repository,它增强了域解决业务用例的能力。
因此,我们可以得出结论,当应用程序从以数据为中心转向面向业务时,Repository 模式被证明是一种更好的方法。
🚀 译自《DAO vs Repository Patterns》
相关文章:
【Spring】DAO 和 Repository 的区别
DAO 和 Repository 的区别 1.概述2.DAO 模式2.1 User2.2 UserDao2.3 UserDaoImpl 3.Repository 模式3.1 UserRepository3.2 UserRepositoryImpl 4.具有多个 DAO 的 Repository 模式4.1 Tweet4.2 TweetDao 和 TweetDaoImpl4.3 增强 User 域4.4 UserRepositoryImpl 5.比较两种模式…...
高阶面试-秒杀系统的设计
场景 特价商品如茅台,在8月1日22点10分0秒开始秒杀 平台用户量:几千万,预计几十万用户感兴趣 需求 临时性的活动,不要太大技术改动 原则 商品不能超卖下单成功的订单不能丢失服务器和数据库不能崩溃尽量不让机器人抢走商品 …...
四十五、 证券基金业数据出境有无特别规范需要注意?
证券基金业数据合规除应遵守本《实务问答》前述的各项通用规定外,还应注意中国证券监督管理委员会等其他机构发布的相关规范。其中,与数据出境相关的主要包括《证券期货业数据分类分级指引》(JR/T 0158—2018,2018年 9月 27日实施…...
02.Linux下安装FFmpeg
目录 一、下载FFmpeg的编译源码 二、编译源码 三、ffmpeg工具结构解析 1、bin目录 2、include库 3、lib库 四、注意事项 五、可能出现的一些问题 1、某些工具未安装/版本过久 2、缺少pkg-config工具 3、缺少ffmplay FFmpeg 是一个开源的跨平台音视频处理工具集&…...
华为RH2288H V2服务器,远程端口安装Linux操作系统
1、管理口 每台服务器的管理口不一样的,假如我的管理IP地址为:192.168.111.201 使用网线,将管理口和自己电脑连接起来,自己ip地址设置成和管理ip同一网段。 使用 ie 浏览器,如果是Edge,必须在Internet Exp…...
JS在线加密简述
JS在线加密,是指:在线进行JS代码混淆加密。通过混淆、压缩、加密等手段,使得JS源代码难以阅读和理解。从而可以有效防止代码被盗用或抄袭,保护开发者的知识产权和劳动成果。常用的JS在线加密网站有:JShaman、JS-Obfusc…...
理想汽车提出3DRealCar:首个大规模3D真实汽车数据集
理想提出3DRealCar,这是第一个大规模 3D 实车数据集,包含 2500 辆在真实场景中拍摄的汽车。我们希望 3DRealCar 可以成为促进汽车相关任务的宝贵资源。 理想汽车提出3DRealCar:首个大规模3D真实汽车数据集! 我们精心策划的高质量3DRealCar数…...
HTML5文旅文化旅游网站模板源码
文章目录 1.设计来源文旅宣传1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 文旅之行界面演示1.5 文旅之行文章内容界面演示1.6 关于我们界面演示1.7 文旅博客界面演示1.8 文旅博客文章内容界面演示1.9 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目…...
山东大学多核并行2024年回忆版
2024.6.13回忆版 矩阵向量乘不可整除代码 集合通信与点对点通信的区别 块划分、循环划分、循环块划分(14个向量,4个进程) 按行访问还是按列访问快 SISD系统问题 循环依赖问题 问题:为什么不能对这个循环并行化࿰…...
CentOS 7 上搭建 JavaEE 环境
CentOS 7 上搭建 JavaEE 环境 安装 Java 环境 1)检查系统中是否已安装 Java java -version如果未安装,将返回提示信息。 2)安装 Java 8 sudo yum install java-1.8.0-openjdk3)配置 Java 环境变量,编辑 /etc/prof…...
库与表管理的终极指南
数据库的库和表的管理 库的管理1.库的创建2.数据库的查看和使用3.数据库的修改4.数据库的删除 表的管理1.表的创建2.表的修改3.表的删除4.查看一个表 阅读指南: 本文章是数据库教程系列的一部分,专注于数据库的库和表管理。读者可以根据兴趣选择阅读相关…...
等级保护测评在测评中Linux系统怎么改
在等级保护测评中,针对Linux系统的整改主要是为了提高其安全性,使之符合等级保护的基本要求。 以下是一些常见的整改步骤和建议: 1. 身份鉴别: • 强化密码策略,例如设置复杂的密码规则、密码长度、密码复杂度、密码…...
Python项目开发实战:微信跳一跳辅助工具,案例教程编程实例课程详解
一、项目背景与意义 微信跳一跳是微信推出的一款小游戏,玩家需要控制一个小人从一个平台跳到另一个平台上,每成功跳过一个平台,分数就会增加。然而,随着游戏难度的增加,玩家需要更精准的控制和更快的反应速度,这往往让许多玩家感到力不从心。因此,开发一款微信跳一跳的辅…...
STM32 SWD烧写
最小电路 stm32f103x 内部已经集成了振荡电路,可以省略;rst引脚电路,可以省略,boot0,boot1不需要设置 正常烧录 -------------------------------------------------------------------STM32CubeProgrammer v2.9.0 …...
数据库系统概论(第5版教材)
第一章 绪论 1、数据(Data)是描述事物的符号记录; 2、数据库系统的构成:数据库 、数据库管理系统(及其开发工具) 、应用程序和数据库管理员; 3、数据库是长期存储在计算机内、有组织、可共享的大量数据的集合&…...
算法力扣刷题 二十六【459.重复的子字符串】
前言 字符串篇,继续。 记录 二十六【459.重复的子字符串】 一、题目阅读 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例…...
【Linux】虚拟机安装openEuler 24.03 X86_64 教程
目录 一、概述 1.1 openEuler 覆盖全场景的创新平台 1.2 系统框架 1.3 平台框架 二、安装详细步骤 一、概述 1.1 openEuler 覆盖全场景的创新平台 openEuler 已支持 x86、Arm、SW64、RISC-V、LoongArch 多处理器架构,逐步扩展 PowerPC 等更多芯片架构支持&…...
分布式事务:理论与实践
分布式事务:理论与实践 在现代分布式系统中,分布式事务是一种确保跨多个独立系统的一致性和完整性的方法。本文将介绍分布式事务的基本概念、实现方式、在Java中的具体实现以及在实际应用中的案例。 分布式事务的基本概念 分布式事务涉及多个独立的数…...
5、双足机器人mpc动力学模型
为计算机器人的当前实际状态x,需要建立双足质心动力学模型。 速度模型由控制输入变量推导速度公式: x向速度νx :当前机器人x方向的前进速度,初始值由速度传感器实时测量得到。y向速度νy :机器人y方向的平移速度。z向速度νz :垂直方向的速度,对于双足机器人行走时为0:…...
虚拟机配置与windows之间文件夹共享samba服务:
虚拟机配置与windows之间文件夹共享samba服务: #输入安装命令: 第一步: 下载samba cd /etc/ sudo apt-get install samba第二步: 配置用户 sudo smbpasswd -a 虚拟机用户名第三步: 进入配置文件配置共享文件 sudo vim /etc/samba/smb.conf末尾输入以下内容: [s…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
