Java泛型DAO通过解耦操作契约与实体类型实现通用数据操作:定义精简泛型接口(findById、save等),子接口扩展业务方法,构造时传入Class获取类型信息,并严格划分职责边界,DAO仅负责数据搬运。

Java 中用泛型规范 DAO 层的通用数据操作,关键是把“操作契约”和“实体类型”解耦,让一套接口能安全、清晰地适配任意业务实体,同时不牺牲可读性与可维护性。
定义精简的泛型接口
泛型 DAO 接口只声明所有实体共有的基础行为,不掺杂业务条件或分页逻辑:
- T findById(ID id):按主键查单条,查不到返回 null 或 Optional
- void save(T entity):统一处理插入或更新(依据主键是否为空)
-
List
findAll() :全量查询,生产环境慎用,建议标记为 @Deprecated - long count():轻量统计,比加载全部对象高效得多
- boolean existsById(ID id):存在性判断,比查实体更省资源
- void deleteById(ID id) 和 void delete(T entity):两种删除入口,后者需确保主键非空
用继承实现业务扩展
通用接口不包办一切,具体业务需求通过子接口补充:
- 定义 UserDao extends GenericDao
,自动获得所有通用方法 - 在 UserDao 中额外声明 List
findByEmail(String email) 或 ListfindByStatus(int status) - 这样既复用通用能力,又保持语义明确,避免泛型接口膨胀成“万能但难懂”的大杂烩
运行时获取实体类型信息
Java 泛型擦除后无法直接用 T.class,需显式传入类型参数来支撑反射或 ORM 操作:
- 推荐方式:实现类构造时接收
Class,如new JpaGenericDao(User.class) - 若用 Spring Data JPA,JpaRepository 已内置类型推导,无需手动传参
- 自研框架中,避免依赖子类反射提取泛型(如 ParameterizedType),因它对代理、匿名类等场景支持弱且易出错
职责边界要划清楚
DAO 层只做数据搬运,不越界承担其他职责:
- 事务控制放在 Service 层,DAO 方法不加
@Transactional - 缓存逻辑(如
@Cacheable)也由 Service 封装,DAO 不引入 RedisTemplate 等缓存组件 - 分页、排序、多条件查询等属于业务特征,不在泛型接口中定义,交由具体 DAO 实现或 Service 组装
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











