核心是用泛型接口解耦操作行为、数据实体与数据源归属,定义idao、idatasourceaware及业务接口,并为不同数据源提供专用泛型基类,结合运行时类型绑定与统一异常事务处理。

核心是用泛型接口把“操作行为”“数据实体”和“数据源归属”三者解耦,而不是让一个DAO硬撑所有数据库。
定义分层泛型接口,明确职责边界
接口不写SQL,只声明能力与语义:
-
IDataSourceAware
:仅负责标记上下文,比如提供 useTenant(String tenantId)或withDataSource(String name)方法,不执行任何数据库操作 -
IDao
:纯行为契约,含 save(T)、findById(ID)、deleteById(ID)等通用方法;建议约束T extends BaseEntity,确保有getId()和乐观锁字段 -
IUserDao extends IDao
& IDataSourceAware :业务层接口,继承通用能力,再叠加语义方法如findByEmailAndTenant(String email, String tenantId)
按数据源类型提供泛型基类,避免强求“一套通吃”
不同数据库的 SQL 能力、事务模型、连接管理方式差异大,应为每类数据源建专用抽象基类:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- JDBC 系(MySQL/PostgreSQL):写
AbstractJdbcDao<t></t>,内部持DataSourceRouter,每次执行前调用lookupDataSource(name)获取连接 - MyBatis-Plus:Mapper 接口继承
BaseMapper<t></t>,配合@MapperScan指向动态SqlSessionTemplate,模板由租户或业务域决定 - JPA:定义
JpaDao<t id> extends JpaRepository<t id></t></t>,搭配AbstractRoutingDataSource,重写determineCurrentLookupKey(),根据线程变量返回数据源名
运行时联动泛型类型与数据源路由
泛型本身不参与运行时决策,但可通过反射+上下文完成绑定:
- 在
AbstractJdbcDao<t></t>中,通过ParameterizedType获取子类传入的T,检查其注解如@TableSchema("user_db")或@TenantIsolated,自动匹配数据源名 - 用
ThreadLocal存当前租户ID,DataSourceRouter拼接T.class.getSimpleName() + "_" + tenantId作为 key,查预加载的Map<string datasource></string> - 避免每次反射:启动时扫描所有 DAO 实现类,缓存
Class> → DataSourceKey映射表,后续直接查表
统一异常与事务语义,屏蔽底层差异
上层业务不应感知 MySQL 的 SQLException 或 JPA 的 PersistenceException:
- 所有 DAO 基类统一抛出自定义异常,如
DataAccessException,包装原始异常并附带上下文(数据源名、实体类型、操作动作) - 事务控制交由切面或模板方法统一管理,例如
@Transactional注解作用在IDao方法上时,自动绑定当前数据源事务管理器 - 对批量操作、分页查询等高频场景,封装成泛型模板方法,保证各数据源实现一致的行为契约
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










