MyBatis 多数据源配置为何越来越长MetaLite 如何按组复用连接参数摘要多数据源的难点不只是创建多个DataSource还包括业务分组、主从角色、路由、连接池参数复用和启动期校验。MetaLite ORM 用orm.jdbc.data-source-groups描述数据源组组内区分 master/slave由Dao(dataSourceGroup...)建立 DAO 与分组的稳定关系同组后续 MySQL 地址还可以继承首个完整 URL 的协议、端口、库参数与凭证减少重复配置。MyBatis 项目接入第二个数据源时常见做法是再定义一套DataSource、SqlSessionFactory、TransactionManager和 Mapper 扫描范围。数据源继续增加后配置类会快速膨胀。动态数据源组件能缓解这个问题但团队仍需回答哪些库属于同一业务谁是主库、谁是从库路由发生在什么层事务如何固定连接MetaLite ORM 把这些问题收敛为“数据源组”。一、数据源组不是连接池列表而是业务边界JdbcProperties的配置前缀是orm.jdbc核心字段是dataSourceGroups。每个DataSourceGroup包含name业务分组名称dbType数据库类型druid该组连接池参数masterList候选写库slaveList候选读库。DAO 使用Dao(dataSourceGroup order)绑定业务组而不是硬编码某个 IP 或连接池 Bean 名称。这层间接关系很重要数据库实例可以扩容、下线或切换DAO 的业务归属不需要跟着变化。二、配置示意先描述组再描述主从实例下面示例只展示结构账号密码在生产环境应来自安全配置中心或环境变量orm:jdbc:data-source-groups:-name:orderdb-type:MYSQLdruid:initial-size:2min-idle:2max-active:20max-wait:3000validation-query:SELECT 1test-while-idle:truemaster-list:-url:jdbc:mysql://db-master:3306/order_db?useUnicodetrueusername:${ORDER_DB_USER}password:${ORDER_DB_PASSWORD}slave-list:-url:db-slave-1/order_db-url:db-slave-2/order_dbJdbcTemplateManager初始化该组后会分别维护读写JdbcTemplate并记录数据库类型。三、为什么首个 URL 完整、后续地址可以精简同一个数据源组的实例通常共享JDBC 协议与驱动参数端口数据库名或路径规则用户名与密码。MetaLite 当前实现要求第一个数据源提供完整 MySQL JDBC URL。后续实例可以只提供 host/path管理器从首个 URL 解析并补齐前缀、端口、查询参数和凭证。收益是减少主从实例间的大段重复配置也降低修改连接参数时漏改某一项的概率。但边界同样明确当前 URL 解析逻辑针对 MySQL。即使DbTypeEnum为扩展预留了位置也不能据此宣称其他数据库已经拥有同等继承能力。四、主从路由不是在业务代码里写 if写操作调用getWriteJdbcTemplate候选集合来自masterList读操作调用getReadJdbcTemplate候选集合来自slaveList。具体选择交给 DAO 实现的DbRouter默认写路由选择第一个主库默认读路由随机选择一个从库没有从库或事务内强制读主时读取写库项目可覆盖路由实现租户、地域或一致性哈希策略。因此“组”负责声明资源“路由器”负责单次决策两者职责没有混在一起。当前实现还有一个值得在多组环境中重点回归的边界getReadJdbcTemplate先用全局readJdbcTemplateMap.isEmpty()判断是否存在从库。如果 A 组没有 slave、B 组配置了 slave全局 Map 已不为空A 组读取就不能只依赖这次全局判断。部署这种“部分组有从库、部分组没有”的组合前应补充分组级判空或测试验证不能只看单组示例。五、Druid 参数为何放在组级别Druid配置对象包含初始连接数、最小空闲、最大活跃、等待时间、空闲检测、保活、PreparedStatement 等参数。同组实例承担相似业务负载复用一套连接池策略通常比每个实例复制一份配置更容易治理。初始化时这些参数会统一应用到组内数据源。如果主库与从库确实需要完全不同的连接池容量当前组级模型就不够细需要拆组或扩展配置模型。这也是应提前评估的约束。六、启动期初始化比运行时第一次访问更容易排障JdbcTemplateManager会在初始化阶段构建各组数据源并在销毁阶段关闭连接池。这样做的工程收益是配置缺失、URL 不合法等问题尽量在启动时暴露DAO 不承担连接池生命周期Seata 模块可以统一代理已经登记的数据源读写模板和数据库类型拥有集中索引。代价是数据源很多时启动成本更高且某个非核心库故障可能影响应用启动。是否需要懒加载应根据系统可用性策略决定。七、多数据源真正危险的是事务与路由错位进入 MetaLite 编程式事务后第一次 DAO 操作才绑定实际 DataSource。绑定完成后后续 DAO 必须留在同一个物理数据源。这条限制防止“一个本地事务悄悄跨库”造成错误承诺。跨库写入需要 Seata、事务消息或业务补偿而不是再切一次数据源键。八、与 MyBatis 多数据源方案如何选择继续使用 MyBatis 更合适的情况已有成熟动态数据源与 Mapper 体系SQL 类型复杂并依赖多个 SqlSession 插件数据源数量少显式配置并不构成负担。MetaLite 数据源组更有价值的情况DAO 需要稳定绑定业务分组而实例会变化主从路由、事务绑定和连接参数复用需要统一希望同一套 DAO 工程规范同时管理数据访问与基础设施生命周期。多数据源配置不是把 YAML 写短就结束了。真正的目标是让业务分组、实例角色、路由算法和事务边界各自有明确位置。框架简介MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。源码基线JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3具体组件版本以项目backend-bom为准。作者简介15 年 Spring 体系企业级开发经验专注于 Java 微服务架构、工程治理与生产实践。持续更新MetaLite 系列内容将持续更新围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者及时获取后续内容。在线演示演示地址: https://admin.metalite.top/演示账号: guess演示密码: admin2026