多态通过统一数据访问接口实现数据库无感切换,各数据库提供具体实现类封装方言差异,运行时由工厂或Spring的AbstractRoutingDataSource根据上下文动态路由。

多态本身不直接“切换数据库”,但它为无感切换提供了关键的抽象能力——把不同数据库的操作统一成同一套接口,让上层代码完全不用关心底层是 MySQL、Oracle 还是 PostgreSQL。真正完成动态切换的是运行时根据上下文选择具体实现类的过程,而多态确保这个过程对业务逻辑透明。
定义统一的数据访问契约
核心是设计一个抽象的数据访问接口或基类,封装所有数据库共有的行为,比如连接、查询、更新、事务控制等。这个接口不绑定任何具体数据库驱动或连接细节。
- 接口方法应聚焦语义而非实现,例如 executeQuery(String sql)、save(Object entity),而不是 executeMysqlSelect()
- 避免在接口中暴露 JDBC 特有类型(如 Connection、PreparedStatement),改用泛型或领域对象封装
- 可配合泛型增强类型安全,如 <T> List<T> findAll(Class<T> type)
为每种数据库提供具体实现
每个数据库驱动对应一个实现类,它们都实现上述统一接口。这些类内部封装了该数据库特有的连接池配置、SQL 方言适配、异常转换等逻辑。
- MySQL 实现类负责处理 LIMIT 分页、反引号字段名、tinyint 布尔映射等细节
- PostgreSQL 实现类处理双引号标识符、JSONB 字段操作、序列生成策略
- Oracle 实现类处理 ROWNUM 分页、LOB 类型处理、SCHEMA 前缀规则
- 所有实现类对外暴露的方法签名完全一致,仅内部实现不同
通过工厂或上下文动态返回具体实例
业务代码不 new 具体实现类,而是通过一个中心化机制获取当前需要的数据访问对象。这个机制基于运行时条件(如租户 ID、操作类型、配置标记)决定返回哪个实现。
- 使用 ThreadLocal 存储当前线程所属的数据源标识(如 “tenant_001” 或 “read_slave”)
- 工厂类根据该标识从注册表中查出对应实现类的 Bean(Spring 管理)或实例
- 调用方拿到的始终是接口类型变量,编译期和运行期都只依赖契约,不感知具体驱动
- 切换只需改变上下文标识,无需修改任何 DAO 调用代码
与 Spring 的 AbstractRoutingDataSource 协同工作
在 Spring 生态中,多态接口常与 AbstractRoutingDataSource 配合:前者解决“操作行为抽象”,后者解决“连接物理路由”。两者分层协作,各司其职。
- 你的 Service 层调用的是多态接口(如 DataAccessor),它内部委托给 JdbcTemplate 或 MyBatis SqlSession
- JdbcTemplate 底层使用的 DataSource 是 DynamicDataSource,它继承 AbstractRoutingDataSource
- DynamicDataSource 的 determineCurrentLookupKey() 方法读取 ThreadLocal 中的标识,返回 key(如 “mysql_master”)
- Spring 容器已将所有具体数据源(mysqlDS、pgDS、oracleDS)注入 DynamicDataSource 的 targetDataSources Map 中


















