mysql数据库动态连接池配置实战方案
Spring Boot MyBatis Dynamic DataSourcebaomidou的生产级动态连接池实战方案。这套方案专门针对多库读写分离 / 多租户 / 分库场景重点解决连接池配置、动态切换、资源隔离、线上事故排查。一、整体架构先看大局Controller ↓ Service (DS(slave)) ↓ Mapper (MyBatis) ↓ SqlSessionFactory ↓ DynamicDataSource ├── master (HikariCP) ├── slave (HikariCP) └── report (HikariCP) ↓ MySQL核心优势一个 Service 方法一个注解切换数据源每个数据源独立连接池互不干扰支持运行时动态调整参数二、依赖配置关键Maven 依赖dependencies!-- MyBatis --dependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion3.0.3/version/dependency!-- Dynamic Datasource --dependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot-starter/artifactIdversion4.2.0/version/dependency!-- MySQL Driver --dependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactIdscoperuntime/scope/dependency/dependencies三、Dynamic DataSource 连接池配置YAML 核心✅ 生产推荐配置HikariCP# 全局 HikariCP 配置 datasource:# 全局生效所有 datasource 都会继承type:com.zaxxer.hikari.HikariDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverhikari:# 基础行为 auto-commit:false# 全局关闭自动提交非常重要connection-test-query:SELECT 1# 心跳检测connection-timeout:3000# 获取连接超时idle-timeout:600000# 空闲超时10分钟max-lifetime:1800000# 连接最大生命周期30分钟validation-timeout:1000# 校验超时leak-detection-threshold:60000# 连接泄漏检测仅建议在调试或排查连接泄漏问题时开启生产稳定运行后可考虑关闭(设为0)或设较大值# 池大小兜底值可被单数据源覆盖minimum-idle:10maximum-pool-size:30# 监控 调试 pool-name:GlobalHikariCP# 默认池名单数据源可覆盖register-mbeans:true# JMX监控生产建议开启# 动态数据源 dynamic:hikari-metrics:enabled:true# 启用多数据源 Hikari 指标收集,监控# 默认数据源名称对应下方 datasource 下的某个keyprimary:master# 严格模式true-未匹配到数据源时直接报错false-未匹配时使用默认数据源strict:truedatasource:# 主库写操作master:# JDBC连接地址指定数据库IP、端口、库名及连接参数# useSSLfalse禁用SSL内网环境常用# serverTimezoneUTC设置时区为UTC# rewriteBatchedStatementstrue开启批量插入优化大幅提升性能url:jdbc:mysql://127.0.0.1:3306/order_db?useSSLfalseserverTimezoneUTCrewriteBatchedStatementstrueusername:root# 数据库用户名password:pwd# 数据库密码driver-class-name:com.mysql.cj.jdbc.Driver# MySQL8.x驱动类pool-name:MasterHikariCP# 连接池名称便于监控识别type:com.zaxxer.hikari.HikariDataSource# 连接池类型HikariCPhikari:minimum-idle:10# 最小空闲连接数建议与initialSize一致maximum-pool-size:40# 最大连接池大小根据DB性能和并发调整connection-timeout:3000# 获取连接超时等待 3-5 秒避免线程无限阻塞idle-timeout:600000# 空闲连接存活时间10分钟超时会被释放max-lifetime:1800000# 连接最大存活时间比 MySQL wait_timeout 短 1-2 分钟防止连接失效connection-test-query:SELECT 1# 连接有效性检测SQLMySQL推荐leak-detection-threshold:60000# 连接泄漏检测阈值60秒超过则记录日志auto-commit:false# 禁用自动提交需手动管理事务保证一致性# 从库读操作slave:# 从库连接地址通常配置只读账号url:jdbc:mysql://127.0.0.1:3306/order_db?useSSLfalseserverTimezoneUTCusername:read_user# 只读账号password:pwddriver-class-name:com.mysql.cj.jdbc.Driverpool-name:SlaveHikariCPtype:com.zaxxer.hikari.HikariDataSourcehikari:minimum-idle:20# 从库读多适当提高最小空闲连接maximum-pool-size:60# 从库可承受更高并发增大连接池connection-timeout:2000# 读操作对延迟更敏感缩短超时时间idle-timeout:600000max-lifetime:1800000connection-test-query:SELECT 1auto-commit:false# 读操作也建议关闭自动提交配合事务注解# 报表库业务隔离report:# 独立报表数据库避免大查询影响主业务url:jdbc:mysql://127.0.0.1:3306/report_db?useSSLfalseusername:report_user# 报表专用账号权限最小化password:pwdpool-name:ReportHikariCPtype:com.zaxxer.hikari.HikariDataSourcehikari:minimum-idle:5# 报表查询频率低减少空闲连接maximum-pool-size:15# 限制最大连接防止拖垮报表库connection-timeout:5000# 报表查询可能较慢适当放宽超时idle-timeout:300000# 5分钟空闲释放更快回收资源max-lifetime:1800000auto-commit:false# 报表查询也建议事务控制四、MyBatis 配置非常重要mybatis:configuration:# 开启数据库字段名下划线 - Java对象驼峰命名自动映射如 user_name - userNamemap-underscore-to-camel-case:true# 全局SQL执行超时时间单位秒# 防止慢SQL拖垮数据库连接池建议根据业务QPS和RT调整# 注此配置对事务中的连接有效但对StatementTimeout不生效的情况需配合数据库驱动参数default-statement-timeout:30# 单次批量查询结果集的抓取大小JDBC Fetch Size# 设置为100可减少ResultSet一次性加载到内存的开销适合分页查询或大结果集遍历# 注意MySQL默认不支持游标需配合 useCursorFetchtrue 参数才能生效default-fetch-size:500# MyBatis一级缓存作用域# SESSION同一SqlSession内共享缓存默认易引发脏读问题# STATEMENT每次执行后清空缓存推荐避免事务中读到旧数据local-cache-scope:statement# 可选补充配置根据你的业务场景考虑是否添加# cache-enabled: false # 关闭二级缓存分布式环境下建议关闭# lazy-loading-enabled: true # 开启延迟加载# aggressive-lazy-loading: false # 侵入式延迟加载false按需加载# Mapper XML文件扫描路径# classpath*: 支持多模块Jar包内的XML文件扫描# mapper/**/*.xml 匹配所有mapper目录下的嵌套XML文件mapper-locations:classpath*:mapper/**/*.xml# 可选补充配置# type-aliases-package: com.example.domain # 实体类别名扫描简化XML中的resultType# configuration-properties: ... # MyBatis扩展配置五、Java 代码示例动态切换Service 层切换数据源ServicepublicclassOrderService{DS(master)Transactional(rollbackForException.class)publicvoidcreateOrder(Orderorder){orderMapper.insert(order);}DS(slave)publicOrdergetOrderById(Longid){returnorderMapper.selectById(id);}DS(report)publicListReportDTOqueryReport(){returnreportMapper.query();}}✅规则DS优先级方法 类 全局事务方法内切换数据源无效Spring 事务特性TransactionalpublicvoidprocessOrder(Orderorder){orderMapper.insert(order);// 走 master ✅reportMapper.query();// 期望走 report但实际仍走 master ❌}Spring 的 Transactional 在方法入口处就通过事务管理器获取了连接并绑定到当前线程整个事务生命周期内所有 DB 操作都复用这条连接。后续即使遇到 DS(“report”)动态数据源发现线程已有事务连接切换会被压制。六、10 个 Dynamic DataSource 高频线上问题与解决方案场景 1事务中切换数据源失效现象DS(slave)不生效仍走 master。原因Spring 事务在方法入口绑定数据源。解决方案DS(slave)Transactional(propagationPropagation.REQUIRES_NEW)publicOrdergetOrder(){...}或拆成两个 Service。场景 2Too many connections某库单独爆现象slave 报连接数满master 正常。原因从库连接池maximum-pool-size过大。解决方案每个数据源独立计算maxPoolSize ≈ (CPU * 2) 磁盘数汇总不超过 MySQLmax_connections场景 3连接泄漏最难查现象某个数据源连接数持续增长。解决方案leak-detection-threshold:60000开启后日志会打印堆栈重点检查SqlSession未关闭自定义 JDBC 操作场景 4慢 SQL 拖垮读库现象从库 RT 飙升影响所有读请求。解决方案读库独立连接池限制读库连接数慢 SQL 单独路由到report场景 5主从延迟导致脏读现象刚写完查不到数据。解决方案强制走主库DS(master)publicOrdergetOrder(){...}或业务层延迟读取场景 6动态数据源 MyBatis 一级缓存脏读现象跨数据源查到旧数据。解决方案# 设置一级缓存作用域为 STATEMENT等效于禁用会话级缓存local-cache-scope:statement场景 7批量插入性能差现象10万数据很慢。解决方案# rewriteBatchedStatementstrue 是 ‌MySQL 批量插入性能优化的“开关”‌。# ‌适用场景‌大量数据导入、日志写入、高频插入业务。‌# 推荐配置‌生产环境建议‌始终开启‌除非有特殊的兼容性需求。‌# 配套动作‌代码中必须使用 addBatch() executeBatch()并注意控制批次大小以防包超限控制每批次的行数如每批 500-1000 条。rewriteBatchedStatementstrueDS(master)TransactionalpublicvoidbatchInsert(ListOrderlist){orderMapper.batchInsert(list);}场景 8数据源配置错误导致启动失败现象Cannot find master datasource解决方案strict:false# 启动时跳过上线前务必改回true。场景 9连接被 MySQL 主动断开现象Communications link failure解决方案max-lifetime:1700000确保小于 MySQLshowvariableslikewait_timeout;场景 10压测时某数据源成为瓶颈现象CPU 很低但 QPS 上不去。解决方案动态扩容连接池Nacos RefreshScope增加只读副本拆分热点业务到新数据源七、生产级最佳实践重点✅连接池分配原则数据源用途连接数master写较小slave读较大report报表很小✅永远不要在事务中切换数据源把所有库配成一个连接池忽略leak-detection-threshold✅监控必开HikariCP Metrics → PrometheusDynamic DS 切换日志八、进阶动态数据源 配置中心RefreshScopeConfigurationpublicclassDataSourceConfig{BeanpublicDataSourcedataSource(){returnDynamicDataSource.build();}}支持高峰期动态调大 slave 连接池下线故障数据源