泛型DAO通过解耦数据操作逻辑与实体类型实现CRUD复用,支持MyBatis-Plus的BaseMapper或手写抽象类,需规避复杂查询、统一主键并保持DAO职责纯粹。
泛型在DAO层设计中能有效消除重复代码,让增删改查操作适配任意实体类型,核心是把“数据操作逻辑”和“具体实体类型”解耦。
定义通用DAO接口
用泛型声明接口,约束所有实现类必须支持指定类型的CRUD:
T
代表实体类(如 User、Order),通常要求有主键字段
接口方法不依赖具体表结构,只约定行为:save、findById、update、deleteById、findAll
可配合
extends Serializable
或自定义标识接口(如
)确保类型安全
基于MyBatis-Plus的泛型实现
MyBatis-Plus 提供了
,天然支持泛型,只需让各Mapper接口继承它:
无需写XML,
、
等方法开箱即用
若需扩展通用逻辑(如软删除统一处理),可封装一个
抽象类继承
,再由各Mapper继承它
手写泛型DAO抽象类(JDBC/MyBatis原生场景)
当不使用MyBatis-Plus时,可通过反射+泛型擦除规避类型丢失问题:
抽象类构造时通过
获取子类实际传入的泛型类型
用
(Spring JDBC)或
反射赋值,确保查询结果正确映射到
增删改语句用占位符,字段名可通过注解(如
、
)或反射实体类提取,避免硬编码
关键点:抽象类本身不指定
,而是由子类明确,如
注意事项与边界控制
泛型DAO不是万能模板,需主动规避风险:
复杂查询(多表关联、聚合)不宜强行塞进通用接口,应保留在具体Mapper中
主键策略要统一(如都用Long型id),否则
无法通用;若存在String主键,可定义泛型参数
事务、缓存、分页等横切关注点,建议通过AOP或Service层统一处理,DAO保持纯粹数据访问职责
单元测试时,对泛型基类做一次覆盖验证即可,不必为每个实体重复测基础CRUD
BaseEntityBaseMapperpublic interface UserMapper extends BaseMapper {} public interface OrderMapper extends BaseMapper {} insertselectByIdGenericMapperBaseMappergetGenericSuperclass()TBeanPropertyRowMapperResultSetT@TableId@TableNameTpublic class UserDAO extends GenericDAOfindById(Long id)