核心思路是用接口抽象数据访问层,将具体框架(mybatis/jpa/jdbc)实现细节完全隔离在实现类中,上层业务仅依赖语义清晰的pojo接口,通过di和工厂动态切换实现,确保契约不变时可自由替换技术栈。

核心思路是用接口抽象数据访问层,把具体数据库框架的实现细节完全隔离在实现类里,上层业务代码只依赖接口。
定义清晰的数据访问接口
不暴露任何框架特有的类型(比如 MyBatis 的 SqlSession、JPA 的 EntityManager、JDBC 的 Connection),只定义业务语义明确的方法:
- 接口方法名体现业务意图,例如 findUserById(long id) 而不是 query("SELECT * FROM user WHERE id = ?", id)
- 参数和返回值使用纯 POJO 或标准集合(List/User/Optional),避免框架实体类或代理对象泄漏
- 异常统一包装为自定义业务异常(如 DataAccessException),不抛出 SQLException、PersistenceException 等底层异常
实现类负责适配具体框架
每个数据库框架对应一个独立的实现类,彼此互不影响:
- MyBatis 实现:用 Mapper 接口或 SqlSession 完成映射,但内部封装 SQL 和参数绑定逻辑
- JPA 实现:用 Repository 或 EntityManager 执行操作,但不暴露 Entity 类型给调用方(返回 DTO 或 VO)
- JDBC 实现:手写 PreparedStatement,做结果集到对象的手动映射
- 切换时只需替换 Spring 配置中的 bean 实现类,或改用 @Conditional 注解动态加载
借助工厂或依赖注入控制实现选择
运行时决定使用哪个实现,而不是编译期硬编码:
- Spring 中用 @Profile 或 @ConditionalOnProperty 指定不同环境启用不同实现
- 通过简单工厂返回接口实例,工厂内部根据配置创建 MyBatisUserDao 或 JpaUserDao
- 避免在 service 层 new 具体实现类,确保所有 DAO 获取都走 DI 容器
测试与演进保障隔离性
验证封装是否真正生效:
- 对 DAO 接口写单元测试,用 Mock 框架模拟行为,不启动任何数据库或框架
- 更换实现后,只要接口契约不变,所有 service 测试应全部通过
- 新增字段或查询逻辑时,只修改接口定义和对应实现,不牵连上层调用方
关键不在技术多高级,而在边界划得够干净——接口即契约,实现可替换,变化不出门。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











