抽象类在DAO层通过泛型基类(如BaseDao<T>)封装通用能力(SqlSession获取、校验等),强制子类实现标准CRUD抽象方法,结合MyBatis-Plus BaseMapper规范接口,避免硬编码SQL及越界承担事务或数据源职责。

抽象 DAO 基类统一基础操作
定义一个泛型抽象类(如 BaseDao<T>),封装所有 DAO 共享的底层能力:获取 SqlSession、事务控制钩子、日志记录、空值校验等。它不实现具体 SQL,只提供可被子类安全调用的受保护方法。
- 构造方法可接收 Mapper 接口 Class,用于反射获取对应 Mapper 实例
- 定义 protected final SqlSession getSqlSession(),由子类按需调用
- 提供 protected void checkNotNull(T entity) 等工具方法,避免重复校验
强制子类实现业务级 CRUD 模板
在抽象类中声明抽象方法(如 save(T entity)、findById(Long id)),要求每个具体 DAO 必须提供实现。这确保了各业务模块至少具备标准增删改查入口,且命名与语义符合团队规约(例如统一用 save 而非 insert)。
- 方法签名明确参数和返回类型,避免子类随意变更契约
- 可配合 Javadoc 注释说明预期行为(如 save 应支持主键自增或 UUID 生成)
- 不建议在抽象类中提供默认实现——除非是纯通用逻辑(如批量插入的分页切片)
结合 MyBatis 的 Mapper 继承体系
MyBatis 本身不支持 DAO 接口继承抽象类,但可通过“抽象基类 + 接口代理”方式协同:让具体 DAO 接口继承通用 Mapper 接口(如 BaseMapper<UserDO>),再由 Service 层调用时依赖抽象 BaseDao 提供的执行上下文。
- 推荐使用 MyBatis-Plus 的 BaseMapper<T> 作为接口层规范,它已内置 insert、selectById 等标准方法
- 若需扩展(如软删除统一处理),可在抽象 DAO 中重写 deleteById,内部调用 BaseMapper 的 update 方法并注入逻辑
- 避免在抽象类里硬编码 SQL —— SQL 应始终放在 XML 或 @Select 注解中,保持可维护性
规避常见设计陷阱
抽象类不是万能胶,用错位置反而增加耦合。数据库层尤其要注意边界清晰:
立即学习“Java免费学习笔记(深入)”;
- 不把事务管理逻辑塞进抽象 DAO —— 事务应由 Service 层控制(@Transactional)
- 不将数据库连接、数据源配置放入抽象类 —— 这属于 Spring 容器职责
- 不为不同数据库(MySQL/Oracle)写同一抽象类分支 —— 应通过方言适配器或运行时策略分离
- POJO 字段命名仍需遵守规约:布尔字段不用 isDeleted,而用 deleted,防止 ORM 反射失败


















