怎么去写java的dao

怎么去写java的dao

Java的DAO需先定义接口声明CRUD方法,再实现类完成具体数据库操作,利用JDBC等技术实现数据交互...

优惠价格:¥ 0.00
当前位置:首页 > 后端开发 > 怎么去写java的dao
详情介绍
Java的DAO需先定义接口声明CRUD方法,再实现类完成具体数据库操作,利用JDBC等技术实现数据交互

Java应用中,DAO(Data Access Object,数据访问对象)作为系统架构的关键组件,负责封装所有与数据库交互的细节,实现业务逻辑和底层持久化存储之间的解耦,以下是详细的实现步骤和最佳实践:

理解DAO的核心职责

  • 单一职责原则:每个DAO类仅对应一张数据库表或视图,专注于该实体的CRUD操作(增删改查),UserDao处理用户相关的所有数据请求,避免与其他模块耦合;
  • 资源管理自动化:确保连接泄露问题通过try-with-resources或框架提供的自动提交机制解决;
  • 异常分层转化:将SQLException转换为自定义的业务异常,使上层调用方无需关心底层错误类型。

基础实现方式(纯JDBC)

定义领域模型(Entity Class)

public class Book {
    private Long id;          // 主键
    private String title;     // 书名
    private String author;    // 作者
    // getters/setters省略...
}

注意:属性名需与数据库列名映射一致,建议使用驼峰命名法配合结果集元数据处理工具。

创建DAO接口规范操作行为

方法签名 功能描述 参数示例 返回值类型
int add(Book entity) 插入新记录 Book对象 受影响行数
boolean deleteById(Long id) 根据ID删除 Long型主键值 是否成功布尔值
Book findById(Long id) 主键查询 Long型主键值 Book实体或null
List<Book> findAll() 获取全表数据 List集合
int update(Book entity) 更新现有记录 Book对象 受影响行数

手写实现类处理原始JDBC操作

public class JdbcBookDaoImpl implements BookDao {
    private final DataSource dataSource; // 依赖注入的数据源
    @Override
    public int add(Book book) {
        String sql = "INSERT INTO books(title, author) VALUES(?, ?)";
        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, book.getTitle());
            pstmt.setString(2, book.getAuthor());
            return pstmt.executeUpdate();
        } catch (SQLException e) {
            throw new DataAccessException("新增书籍失败", e);
        }
    }
    @Override
    public Book findById(Long id) {
        String sql = "SELECT  FROM books WHERE id=?";
        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setLong(1, id);
            ResultSet rs = pstmt.executeQuery();
            if (rs.next()) {
                return mapResultSetToEntity(rs); // 手动映射结果集到对象
            }
            return null;
        } catch (SQLException e) {
            throw new DataAccessException("查询书籍失败", e);
        }
    }
    private Book mapResultSetToEntity(ResultSet rs) throws SQLException {
        Book book = new Book();
        book.setId(rs.getLong("id"));
        book.setTitle(rs.getString("title"));
        book.setAuthor(rs.getString("author"));
        return book;
    }
}

关键点:①始终使用预编译语句防止SQL注入;②合理设置事务隔离级别;③结果集到对象的手动转换需要特别注意类型匹配。

进阶方案(整合MyBatis框架)

当项目复杂度提升时,推荐采用成熟的ORM解决方案:

XML映射文件配置示例(BookMapper.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.BookMapper">
    <resultMap id="BaseResultMap" type="Book">
        <id column="id" property="id"/>
        <result column="title" property="title"/>
        <result column="author" property="author"/>
    </resultMap>
    <select id="selectById" resultMap="BaseResultMap">
        SELECT  FROM books WHERE id=#{id}
    </select>
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO books(title, author) VALUES(#{title}, #{author})
    </insert>
</mapper>

动态代理开发优势对比表

特性 传统手写实现 MyBatis动态代理
代码量 大量重复模板化代码 近乎零配置
SQL可维护性 硬编码在Java文件中 独立XML便于DBA协作
缓存支持 需自行实现 内置一级/二级缓存机制
批量操作效率 循环单条执行 支持collection参数批量插入

设计模式增强扩展性

  • 泛型DAO基类:针对简单CRUD场景抽取公共父类,减少代码冗余。
    public abstract class BaseDao<T extends BaseEntity> {
      public T selectByPrimaryKey(Serializable id) {...}
      public int deleteByPrimaryKey(Serializable id) {...}
      // 其他通用方法声明
    }
  • 装饰器模式应用:通过面向切面编程添加日志、性能监控等功能而不修改原有实现,如使用Spring AOP记录方法执行时间:
    @Aspect
    @Component
    public class DaoPerformanceMonitor {
      @Around("execution( com.example.dao..(..))")
      public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
          long start = System.currentTimeMillis();
          try {
              return joinPoint.proceed();
          } finally {
              System.out.println("方法执行耗时:" + (System.currentTimeMillis() start) + "ms");
          }
      }
    }

工程实践建议

  • 分包策略:按功能模块划分dao包结构(如com.company.projectx.user.dao);
  • 版本控制:将SQL语句纳入Git管理,重要复杂查询建议单独建档;
  • 单元测试覆盖率:针对每个DAO方法编写集成测试验证边界条件;
  • 慢查询分析:定期使用Explain计划优化热点SQL执行路径。

FAQs:
Q1:为什么不应该让Service层直接操作数据库连接?
答:违反单一职责原则和分层架构设计理念,直接耦合会导致事务管理困难、连接池耗尽风险增加,且不利于团队协作时的代码维护,通过DAO统一管控数据访问,可以集中处理加密解密、审计日志等横切关注点。

Q2:如何处理多数据源场景下的DAO设计?
答:可采用抽象工厂模式创建不同环境的DataSource实例,结合Spring的@Qualifier注解指定特定数据源,对于跨库关联查询,建议显式分布式事务管理而非简单的多源切换,确保ACID特性不被

0