DAO模式概述
理解DAO设计模式的概念与价值
学习目标
掌握DAO模式的核心概念与解决的问题
什么是DAO模式?
DAO(Data Access Object)是J2EE核心模式之一,通过抽象数据访问接口,提供业务对象与数据源之间的解耦。
核心思想:分离业务逻辑与数据访问逻辑,提供统一的数据访问接口,隐藏底层数据源实现细节。
为什么需要DAO模式?
没有使用DAO模式的痛点:
- 业务逻辑中混杂SQL/JDBC代码
- 切换数据源需要修改多处代码
- 数据访问逻辑无法复用
- 难以进行单元测试
- 无法统一处理数据访问异常
解耦性
分离业务逻辑与数据访问逻辑,使得业务层无需关心数据存储细节
可替换性
更换数据源(如MySQL→MongoDB)只需修改DAO实现,不影响业务层
可测试性
可以轻松模拟DAO进行业务逻辑单元测试,无需实际数据库
封装性
集中处理数据访问逻辑,避免SQL注入等安全问题
DAO应用场景
- 任何需要数据持久化的应用系统
- 分层架构的数据访问层
- 多数据源切换场景
- 需要数据访问抽象的项目
- 需要单元测试保障的项目
DAO模式核心组件
构成DAO模式的关键元素及其职责
学习目标
理解DAO模式中的各类组件及其协作关系
数据模型(Model)
表示业务数据的Java对象(POJO)
- 包含数据字段与getter/setter
- 不包含业务逻辑
- 通常与数据库表对应
- 示例:User, Product, Order
DAO接口
定义数据访问操作的方法签名
- 不包含具体实现细节
- 定义CRUD操作方法
- 定义查询操作方法
- 示例:UserDAO, ProductDAO
DAO实现类
实现DAO接口的具体逻辑
- 包含实际的数据库操作代码
- 针对特定数据源实现(JDBC、Hibernate等)
- 处理SQL异常与连接管理
- 示例:UserDAOImpl, ProductDAOImpl
DAO模式类图结构
业务层调用
业务对象(BusinessObject)通过DAO接口发起数据访问请求
DAO接口转发
DAO接口将请求路由到具体的DAO实现类
数据访问执行
DAO实现类执行具体的数据源操作(SQL/JDBC等)
结果返回
DAO实现将结果集转换为模型对象返回给业务层
DAO模式实现步骤
手把手实现一个完整的DAO模式
学习目标
掌握从创建数据模型到实现DAO的完整过程
定义数据模型(User)
创建简单的POJO类表示用户数据:
创建DAO接口
定义用户数据访问操作:
实现DAO接口(JDBC版)
使用原生JDBC实现数据访问:
业务层使用DAO
在业务逻辑中使用DAO进行数据访问:
相关模式对比
DAO模式与其他数据访问模式的比较
学习目标
理解不同数据访问模式的使用场景和优劣
DAO模式
特点:每个模型对应一个DAO,提供CRUD操作
优点:
- 简单直接
- 完全控制SQL
- 技术无关实现
缺点:
- 存在代码重复
- 需要手写大量样板代码
Repository模式
特点:以聚合根为中心的数据访问
优点:
- 更面向领域驱动
- 隐藏数据访问细节
- 更好地处理复杂查询
缺点:
- 概念复杂
- 学习曲线陡峭
Active Record模式
特点:模型自身包含数据访问逻辑
优点:
- 简单易用
- 快速开发
- 适合小型应用
缺点:
- 违反单一职责
- 模型与持久化耦合
- 难以测试
Data Mapper模式
特点:对象与数据库完全解耦
优点:
- 完全解耦
- 支持复杂映射
- 高度灵活
缺点:
- 实现复杂
- 性能开销较大
- 需要额外配置
模式选择建议
- DAO:中小型项目,需要直接控制SQL
- Repository:复杂领域模型,遵循DDD
- Active Record:简单CRUD应用,快速原型
- Data Mapper:大型企业应用,需要完全解耦
Spring集成DAO
在现代Spring应用中实现DAO模式
学习目标
掌握在Spring框架中实现DAO的最佳方式
Spring JDBC集成
使用JdbcTemplate简化JDBC操作:
Spring Data JPA
使用Repository接口自动实现DAO:
Spring DAO最佳实践
- 使用Spring的@Repository注解标识DAO类
- 利用依赖注入提供DataSource
- 使用JdbcTemplate处理JDBC样板代码
- 对于新项目,优先考虑Spring Data JPA
- 将数据源配置外部化(application.properties)
- 使用Spring事务管理
常见错误与解决方案
使用DAO模式时的陷阱与防范
过度复杂的DAO接口
问题:DAO接口中定义了过多的业务逻辑方法
解决:
- DAO只负责基本CRUD和简单查询
- 复杂业务逻辑放在服务层
- 使用Specification模式处理复杂查询
DAO层异常处理不当
问题:将SQLException直接抛出到业务层
解决:
- 使用Spring的DataAccessException转换机制
- 定义统一的数据访问异常体系
- 异常信息合理封装,避免暴露底层细节
对象关系映射(N+1)问题
问题:访问关联对象时触发大量查询
解决:
- 使用JOIN FETCH加载关联对象
- 利用二级缓存
- 采用DTO投影代替加载完整对象
资源未正确释放
问题:忘记关闭Connection, Statement, ResultSet
解决:
- 使用try-with-resources语法
- 使用JdbcTemplate等工具类
- 采用连接池管理数据库连接
DAO模式最佳实践
构建高效可靠的DAO层
接口导向设计
始终面向接口编程,依赖抽象而非具体实现
封装数据访问细节
将JDBC/Hibernate等实现细节封装在DAO内部
使用连接池
通过连接池管理数据库连接,提高性能
使用模板方法模式
抽象通用操作,减少重复代码
抽象基类DAO
创建AbstractDao处理通用逻辑:
使用DTO优化性能
避免返回完整领域对象:
动手练习
通过实践巩固DAO模式知识
练习目标
实现一个完整的DAO层,包括多种实现方式
练习1:原生JDBC实现
- 创建User模型类
- 定义UserDAO接口
- 实现JDBC版UserDAOImpl
- 处理数据库连接、SQL执行和结果映射
练习2:Spring JdbcTemplate
- 使用Spring Boot创建项目
- 配置DataSource
- 使用JdbcTemplate重写DAO实现
- 比较与原生JDBC实现差异
练习3:单元测试
- 使用Mockito模拟DAO
- 测试UserService逻辑
- 使用内存数据库测试DAO实现
- 测试异常处理逻辑
练习4:多数据源支持
- 设计支持MySQL和PostgreSQL的DAO
- 使用工厂模式创建不同DAO实现
- 通过配置文件切换数据源
- 验证相同接口不同实现的行为
扩展挑战
- 实现分页查询DAO方法
- 添加事务管理支持
- 实现批处理操作
- 添加二级缓存支持
- 实现软删除模式
- 添加审计字段支持