DAO 类的职责与设计原则

1. DAO 的核心职责

DAO(Data Access Object,数据访问对象)的主要职责是封装对数据的访问逻辑,但它与纯粹的数据实体类(如 DTO、POJO)不同,也与 Service 业务逻辑层不同。

DAO 应该做什么?

✅ 数据访问操作

  • 执行数据库 CRUD(增删改查)操作

  • 提供查询接口(如 findByIdfindAllsavedelete

  • 处理数据库事务(通常由 @Transactional 管理)

✅ 数据转换

  • 将数据库实体(如 UserEntity)转换为业务对象(如 User

  • 处理数据库特有的数据类型(如 LocalDateTime 转换)

✅ SQL/HQL/JPQL 管理

  • 编写 SQL 查询(如 @Query 或 XML 映射)

  • 处理分页、排序等数据库操作

DAO 不应该做什么?

❌ 业务逻辑(属于 Service 层):

  • 例如:计算订单折扣、验证用户权限等

❌ HTTP 请求/响应处理(属于 Controller 层):

  • 例如:解析 @RequestBody、返回 ResponseEntity

❌ 直接暴露数据库细节

  • 例如:不应该让上层直接接触 Connection 或 PreparedStatement


2. DAO 与实体类的区别

类别DAO 类实体类(Entity/DTO)
用途封装数据访问逻辑表示数据结构(数据库表或 API 数据)
是否含逻辑有简单的查询逻辑通常只是数据容器(纯 POJO)
示例UserRepository.findByName()User { id, name, email }
Spring 注解@Repository@Entity(JPA)或 无注解(DTO)

3. DAO 的典型实现方式

(1) Spring Data JPA(推荐)

@Repository
public interface UserRepository extends JpaRepository<User, Long> {// 自动实现基本 CRUDList<User> findByName(String name);  // 方法名自动解析为 SQL@Query("SELECT u FROM User u WHERE u.email LIKE %?1%")List<User> findByEmailContaining(String email);
}

特点

  • 方法名自动生成查询(如 findByName → SELECT * FROM user WHERE name = ?

  • 支持 @Query 自定义 SQL/JPQL

(2) MyBatis(SQL 更灵活)

@Repository
public interface UserMapper {@Select("SELECT * FROM user WHERE id = #{id}")User findById(Long id);@Insert("INSERT INTO user(name, email) VALUES(#{name}, #{email})")void insert(User user);
}

特点

  • 直接写 SQL,适合复杂查询

  • 需配合 XML 或注解映射

 (3) 传统 JDBC(低层控制)

@Repository
public class UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public User findById(Long id) {String sql = "SELECT * FROM user WHERE id = ?";return jdbcTemplate.queryForObject(sql, new UserRowMapper(), id);}
}

特点

  • 完全手动控制 SQL 和执行过程

  • 适合需要高度优化的场景

4. DAO 与 Service 的分工

DAO 层

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {List<Order> findByUserId(Long userId);
}

Service 层(业务逻辑)

@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;public BigDecimal calculateTotalPrice(Long userId) {List<Order> orders = orderRepository.findByUserId(userId);return orders.stream().map(Order::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);}
}

关键区别

  • DAO 只关心怎么查数据findByUserId

  • Service 关心业务计算(如汇总订单金额)


5. 最佳实践

  1. 保持 DAO 单一职责

    • 只做数据访问,不混入业务逻辑。

  2. 使用接口 + 实现

    • 便于替换数据源(如从 MySQL 切到 MongoDB)。

  3. 避免“贫血 DAO”

    • 如果 DAO 只是简单调用 JPA/MyBatis,可以直接用 Repository,无需额外封装。

  4. 事务管理

    • 事务注解(@Transactional)通常放在 Service 层。

DAO(Data Access Object)层 在大多数现代Java应用中,特别是使用 MyBatis 或 JPA 框架时,通常对应你所说的 Mapper 类。不过具体实现方式可能略有不同,取决于你使用的技术栈。下面详细解释它们的关系和区别:

DAO 层和 Mapper 的关系

概念DAO(数据访问对象)Mapper(MyBatis 术语)
定位数据访问层,封装数据库操作MyBatis 对 DAO 的实现方式
技术实现可以是接口或类通常是接口(MyBatis)或 XML 映射文件
Spring 注解@Repository@Mapper(MyBatis)或 @Repository
典型方法insert(User user)findById(Long id)@Select@Insert 等 SQL 注解方法

结论

  • DAO 是一个设计概念,表示数据访问层。

  • Mapper 是 MyBatis 对 DAO 的具体实现方式(用接口+注解或XML定义SQL)。

  • 在 Spring + MyBatis 组合中,Mapper ≈ DAO


总结

  • DAO 类:负责数据访问(查询/存储),有简单逻辑(如 SQL 拼接),但不包含业务规则

  • 实体类:纯数据结构,无逻辑,用于表示数据库表或 API 数据。

  • Service 类:处理业务逻辑,调用 DAO 并组合数据。

合理分层能让代码更清晰、更易维护! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Kubernetes】如何使用 kubeadm 搭建 Kubernetes 集群?还有哪些部署工具?

使用 kubeadm 搭建 Kubernetes 集群是一个比较常见的方式。kubeadm 是 Kubernetes 提供的一个命令行工具&#xff0c;它可以简化 Kubernetes 集群的初始化和管理。下面是使用 kubeadm 搭建 Kubernetes 集群的基本步骤&#xff1a; 1. 准备工作 确保你的环境中有两台或更多的机…

Pycharm(十二)列表练习题

一、门和钥匙 小X在一片大陆上探险&#xff0c;有一天他发现了一个洞穴&#xff0c;洞穴里面有n道门&#xff0c; 打开每道门都需要对应的钥匙&#xff0c;编号为i的钥匙能用于打开第i道门&#xff0c; 而且只有在打开了第i(i>1)道门之后&#xff0c;才能打开第i1道门&#…

在未归一化的线性回归模型中,特征的尺度差异可能导致模型对特征重要性的误判

通过数学公式来更清晰地说明归一化对模型的影响&#xff0c;以及它如何改变特征的重要性评估。 1. 未归一化的情况 假设我们有一个线性回归模型&#xff1a; y β 0 β 1 x 1 β 2 x 2 ϵ y \beta_0 \beta_1 x_1 \beta_2 x_2 \epsilon yβ0​β1​x1​β2​x2​ϵ 其…

JS—页面渲染:1分钟掌握页面渲染过程

个人博客&#xff1a;haichenyi.com。感谢关注 一. 目录 一–目录二–页面渲染过程三–DOM树和渲染树 二. 页面渲染过程 浏览器的渲染过程可以分解为以下几个关键步骤 2.1 解析HTML&#xff0c;形成DOM树 浏览器从上往下解析HTML文档&#xff0c;将标签转成DOM节点&#…

niuhe插件, 在 go 中渲染网页内容

思路 niuhe 插件生成的 go 代码是基于 github.com/ma-guo/niuhe 库进行组织管理的, niuhe 库 是对 go gin 库的一个封装&#xff0c;因此要显示网页, 可通过给 gin.Engine 指定 HTMLRender 来实现。 实现 HTMLRender 我们使用 gitee.com/cnmade/pongo2gin 实现 1. main.go …

openEuler24.03 LTS下安装HBase集群

前提条件 安装好Hadoop完全分布式集群&#xff0c;可参考&#xff1a;openEuler24.03 LTS下安装Hadoop3完全分布式 安装好ZooKeeper集群&#xff0c;可参考&#xff1a;openEuler24.03 LTS下安装ZooKeeper集群 HBase集群规划 node2node3node4MasterBackup MasterRegionServ…

LVGL移植说明

https://www.cnblogs.com/FlurryHeart/p/18104596 参考&#xff0c;里面说明了裸机移植以及freeRTOS系统移植。 移植到linux https://blog.csdn.net/sunchao124/article/details/144952514

ubuntu虚拟机裁剪img文件系统

1. 定制文件系统前期准备 将rootfs.img文件准备好&#xff0c;并创建target文件夹2. 挂载文件系统 sudo mount rootfs.img target #挂载文件系统 sudo chroot target #进入chroot环境3. 内裁剪文件系统 增删裁剪文件系统 exit #退出chroot环境 sudo umount target…

esp826601s固件烧录方法(ch340+面包板)

esp826601s固件烧录方法&#xff08;ch340面包板&#xff09; 硬件 stm32f10c8t6&#xff0c;esp826601s,面包板&#xff0c;ch340(usb转ttl),st_link&#xff08;供电&#xff09; 接线 烧录时&#xff1a; stm32f10c8t6&#xff1a;gnd->负极&#xff0c; 3.3->正极…

Servlet 点击计数器

Servlet 点击计数器 引言 Servlet 是 Java 企业版&#xff08;Java EE&#xff09;技术中的一种服务器端组件&#xff0c;用于处理客户端请求并生成动态内容。本文将详细介绍如何使用 Servlet 实现一个简单的点击计数器&#xff0c;帮助读者了解 Servlet 的基本用法和原理。 …

LangChain vs. LlamaIndex:深入对比与实战应用

目录 引言LangChain 与 LlamaIndex 概述 什么是 LangChain&#xff1f;什么是 LlamaIndex&#xff1f;两者的核心目标与适用场景 架构与设计理念 LangChain 的架构设计LlamaIndex 的架构设计关键技术差异 核心功能对比 数据连接与处理查询与检索机制上下文管理能力插件与扩展性…

【Java中级】10章、内部类、局部内部类、匿名内部类、成员内部类、静态内部类的基本语法和细节讲解配套例题巩固理解【5】

❤️ 【内部类】干货满满&#xff0c;本章内容有点难理解&#xff0c;需要明白类的实例化&#xff0c;学完本篇文章你会对内部类有个清晰的认知 &#x1f495; 内容涉及内部类的介绍、局部内部类、匿名内部类(重点)、成员内部类、静态内部类 &#x1f308; 跟着B站一位老师学习…

内容中台:驱动多渠道营销的关键策略

在数字营销快速发展的今天&#xff0c;企业需要在多个渠道&#xff08;网站、社交媒体、移动应用等&#xff09;上同步管理内容。尽管网站仍是品牌展示的核心&#xff0c;但信息分散、多平台重复创建内容的问题&#xff0c;让营销人员面临巨大的管理挑战。 内容中台&#xff0…

SvelteKit 最新中文文档教程(17)—— 仅服务端模块和快照

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

CMake 中的置变量

在 CMake 中&#xff0c;变量是存储和传递信息的重要方式。以下是一些常用的 CMake 变量&#xff0c;以表格形式列出&#xff0c;包括它们的名称、含义和常见用途&#xff1a; 变量名称含义常见用途CMAKE_CURRENT_SOURCE_DIR当前处理的 CMakeLists.txt 文件所在的源代码目录的…

深入解析C++类:面向对象编程的核心基石

一、类的本质与核心概念 1.1 类的基本定义 类是将**数据&#xff08;属性&#xff09;与操作&#xff08;方法&#xff09;**封装在一起的用户自定义类型&#xff0c;是面向对象编程的核心单元。 // 基础类示例 class BankAccount { private: // 访问控制string owner; …

介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用及数组讲解

Docker 是一种轻量级的容器化技术&#xff0c;能够让开发者将应用程序和其所有依赖项打包成一个独立的容器&#xff0c;实现快速部署和运行。以下是 Docker 的基本概念和优势&#xff1a; 基本概念&#xff1a; 镜像&#xff08;Image&#xff09;&#xff1a;镜像是一个只读的…

在msys2里面的mingw64下面编译quickjs

其实非常的简单&#xff0c;就是正常的make 和make install就行了&#xff0c;这里只是简单的做个编译过程记录。 打开开始--程序--里面的msys64里面的mingw64控制台窗口&#xff0c;切换到quickjs下载解压缩后的目录&#xff0c;执行make和make install ndyHP66G5 MINGW64 ~…

el-table实现表头带筛选功能,并支持分页查询

最开始尝试了下面方法&#xff0c;发现这种方法仅支持筛选当前页的数据&#xff0c;不符合产品要求 于是通过查询资料发现可以结合filter-change事件&#xff0c;当表格的筛选条件发生变化的时候会触发该事件&#xff0c;调接口获取符合条件的数据&#xff0c;实现如下 1、表格…

OpenCV 从入门到精通(day_03)

1. ROI切割 ROI&#xff1a;Region of Interest&#xff0c;翻译过来就是感兴趣的区域。什么意思呢&#xff1f;比如对于一个人的照片&#xff0c;假如我们要检测眼睛&#xff0c;因为眼睛肯定在脸上&#xff0c;所以我们感兴趣的只有脸这部分&#xff0c;其他都不care&#xf…