泛型dao通过解耦数据操作逻辑与实体类型实现crud复用,支持mybatis-plus的basemapper或手写抽象类,需规避复杂查询、统一主键并保持dao职责纯粹。

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










