1. DAO 的核心职责
DAO(Data Access Object,数据访问对象)的主要职责是封装对数据的访问逻辑,但它与纯粹的数据实体类(如 DTO、POJO)不同,也与 Service 业务逻辑层不同。
DAO 应该做什么?
✅ 数据访问操作:
-
执行数据库 CRUD(增删改查)操作
-
提供查询接口(如
findById
,findAll
,save
,delete
) -
处理数据库事务(通常由
@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. 最佳实践
-
保持 DAO 单一职责:
-
只做数据访问,不混入业务逻辑。
-
-
使用接口 + 实现:
-
便于替换数据源(如从 MySQL 切到 MongoDB)。
-
-
避免“贫血 DAO”:
-
如果 DAO 只是简单调用 JPA/MyBatis,可以直接用
Repository
,无需额外封装。
-
-
事务管理:
-
事务注解(
@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 并组合数据。
合理分层能让代码更清晰、更易维护!