DAO(Data Access Object)是Java开发中用于封装数据访问层的核心模式,其核心目标是将业务逻辑与数据操作解耦,通过定义DAO接口规范数据库操作(如增删改查),由具体实现类(如JDBC、Hibernate、MyBatis等)执行SQL与数据库交互,隐藏底层细节,该模式提升代码复用性,便于切换数据源,同时增强系统可维护性与测试性,是分层架构中连接业务层与数据层的重要桥梁,确保数据操作逻辑独立且清晰。
Java DAO模式详解:从数据访问到架构解耦
在Java企业级开发中,数据访问层(Data Access Layer, DAL)是连接业务逻辑与数据库的核心桥梁,而DAO(Data Access Object,数据访问对象)模式作为数据访问层最经典的设计模式之一,以其"解耦关注点、提升可维护性"的核心思想,成为Java开发者必备的设计工具,本文将从DAO模式的概念出发,深入剖析其结构、实现方式及最佳实践,帮助读者掌握这一关键架构模式。
DAO模式:什么是数据访问对象?
DAO模式是一种结构设计模式,其核心目标是将数据访问逻辑与业务逻辑分离,在未使用DAO模式的应用中,业务逻辑层(Service层)常常直接依赖JDBC、Hibernate、MyBatis等数据访问技术,导致代码耦合度高:一旦数据库技术更换(如从MySQL切换到PostgreSQL),或数据访问方式调整(从JDBC切换到JPA),业务逻辑层代码需要大量修改,而DAO模式通过引入"数据访问对象"这一中间层,让业务逻辑层仅通过DAO接口操作数据,无需关心底层数据存储的具体实现。
DAO模式的核心思想
- 关注点分离:业务逻辑层专注业务流程(如用户注册、订单计算),数据访问层专注数据操作(如SQL执行、结果集映射)。
- 抽象与封装:通过接口定义数据操作标准(如增删改查),具体实现由DAO类完成,隐藏底层技术细节。
- 可维护性与可扩展性:更换数据库、优化查询逻辑时,只需修改DAO实现类,无需触动业务代码。
DAO模式的核心组成部分
一个完整的DAO模式实现通常包含以下四个核心组件,它们协同工作,形成清晰的数据访问架构:
DAO接口(DAO Interface)
定义数据操作的抽象方法,是业务逻辑层与数据访问层的"契约",接口中仅声明操作行为,不包含具体实现。
示例:
public interface UserDao {
User findById(Long id); // 根据ID查询用户
void save(User user); // 保存用户
void update(User user); // 更新用户信息
void deleteById(Long id); // 根据ID删除用户
List<User> findAll(); // 查询所有用户
List<User> findByUsername(String username); // 根据用户名查询
}
DAO实现类(DAO Implementation)
实现DAO接口,完成具体的数据访问逻辑,根据底层技术不同,可能是JDBC实现、MyBatis实现、Hibernate实现等。
示例(基于JDBC的实现):
public class UserDaoImpl implements UserDao {
private final DataSource dataSource; // 使用DataSource而非直接Connection
@Override
public User findById(Long id) {
String sql = "SELECT id, username, email FROM users WHERE id = ?";
try (Connection connection = dataSource.getConnection();
PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setLong(1, id);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
User user = new User();
user.setId(rs.getLong("id"));
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
return user;
}
} catch (SQLException e) {
throw new DataAccessException("查询用户失败", e);
}
return null;
}
@Override
public void save(User user) {
String sql = "INSERT INTO users (username, email) VALUES (?, ?)";
try (Connection connection = dataSource.getConnection();
PreparedStatement stmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
stmt.setString(1, user.getUsername());
stmt.setString(2, user.getEmail());
int affectedRows = stmt.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("创建用户失败,没有行受到影响");
}
try (ResultSet generatedKeys = stmt.getGeneratedKeys()) {
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
} else {
throw new SQLException("创建用户失败,ID未获取");
}
}
} catch (SQLException e) {
throw new DataAccessException("保存用户失败", e);
}
}
// 其他方法实现...
}
实体类(Entity/Model)
与数据库表结构对应的Java对象,用于封装数据。users表对应User实体类:
public class User {
private Long id;
private String username;
private String email;
private LocalDateTime createdAt;
// 构造方法
public User() {}
public User(Long id, String username, String email) {
this.id = id;
this.username = username;
this.email = email;
this.createdAt = LocalDateTime.now();
}
// getter/setter方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}
数据源/连接管理(DataSource/Connection Management)
负责数据库连接的获取与释放,通常通过连接池(如HikariCP、Druid)实现,避免频繁创建和销毁连接带来的性能损耗。
示例(HikariCP配置):
public class DataSourceManager {
private static HikariDataSource dataSource;
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC");
config.setUsername("root");
config.setPassword("password");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMaximumPoolSize(10);
config.setMinimumIdle(5);
config.setConnectionTimeout(30000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
dataSource 标签: #DAO