当前位置: 首页 > news >正文

Spring Boot项目里MyBatis-Plus Dynamic-Datasource主数据源失效?别慌,5分钟搞定配置

Spring Boot多数据源配置:彻底解决Dynamic-Datasource主数据源失效问题

刚接触Spring Boot多数据源配置的开发者,经常会遇到一个令人头疼的问题——明明按照文档配置了数据源,却在启动时抛出CannotFindDataSourceException: dynamic-datasource can not find primary datasource异常。这种情况在项目紧急上线或快速迭代时尤为常见,本文将带你深入理解问题根源,并提供多种实用解决方案。

1. 问题现象与核心原因分析

当你在Spring Boot项目中集成MyBatis-Plus的dynamic-datasource组件时,可能会遇到以下典型错误日志:

com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasource

问题本质在于动态数据源组件无法找到默认的主数据源。这通常发生在以下两种场景:

  1. 配置文件中没有声明primary指定的数据源名称对应的具体数据源
  2. 代码中既没有类级别的@DS注解,也没有方法级别的@DS注解

dynamic-datasource组件有一个重要设计原则:当没有明确指定数据源时,默认会尝试使用名为master的数据源。如果此时配置中既没有master数据源,也没有通过primary属性指定其他数据源名称,就会抛出上述异常。

2. 关键配置参数解析

理解dynamic-datasource的两个核心配置参数是解决问题的关键:

2.1 primary参数

spring: datasource: dynamic: primary: master # 设置默认数据源名称
  • 作用:指定默认使用的数据源名称
  • 默认值master
  • 行为:当代码中没有使用@DS注解时,会自动使用此处指定的数据源

2.2 strict参数

spring: datasource: dynamic: strict: true # 严格模式开关
  • 作用:控制数据源匹配的严格程度
  • 默认值false
  • true行为:当指定的数据源不存在时直接抛出异常
  • false行为:当指定的数据源不存在时回退到primary指定的默认数据源

3. 五种实用解决方案对比

根据不同的项目需求和场景,可以选择以下任一方案解决问题:

3.1 方案一:添加类级别@DS注解

@DS("lizzDB") // 指定该类默认使用lizzDB数据源 @Repository public class ErmDaoImpl implements ErmDao { // 类实现... }

适用场景

  • 整个类的所有方法都使用同一个数据源
  • 不想修改现有配置文件的场景

优缺点对比

优点缺点
改动最小,只需添加一个注解如果类中方法需要使用不同数据源则不适用
不影响现有配置需要在每个类上添加注解

3.2 方案二:配置primary指定的数据源

spring: datasource: dynamic: primary: lizzDB # 指定默认数据源名称 lizzDB: # 配置对应的数据源 url: jdbc:mysql://localhost:3306/lizz_db username: user password: pass

适用场景

  • 项目中有明确的默认数据源
  • 希望保持配置集中管理的项目

3.3 方案三:添加master数据源配置

spring: datasource: dynamic: primary: master # 使用默认值 master: # 添加master数据源配置 url: jdbc:mysql://localhost:3306/default_db username: user password: pass lizzDB: url: jdbc:mysql://localhost:3306/lizz_db username: user password: pass

适用场景

  • 希望保持与组件默认行为一致的项目
  • 需要向后兼容已有配置的场景

3.4 方案四:关闭strict模式

spring: datasource: dynamic: strict: false # 关闭严格模式

行为变化

  • 当指定的数据源不存在时,不会抛出异常
  • 自动回退到primary指定的默认数据源

适用场景

  • 需要更高容错性的开发环境
  • 数据源动态变化的特殊场景

3.5 方案五:混合配置策略

对于复杂项目,可以采用组合策略:

spring: datasource: dynamic: primary: default_db # 业务主库 strict: true # 生产环境建议开启 default_db: # 主业务库 url: jdbc:mysql://localhost:3306/main_db username: user password: pass report_db: # 报表库 url: jdbc:mysql://localhost:3306/report_db username: user password: pass

同时在代码中合理使用@DS注解:

@Service @DS("default_db") // 类级别默认数据源 public class OrderServiceImpl implements OrderService { @Autowired private ReportDao reportDao; @DS("report_db") // 方法级别覆盖 public Report generateDailyReport() { // 使用报表库生成报告 } }

4. 最佳实践与常见陷阱

在实际项目开发中,我们总结出以下经验:

4.1 配置建议

  1. 生产环境配置

    spring: datasource: dynamic: primary: main_db strict: true # 生产环境建议开启严格模式
  2. 开发环境配置

    spring: datasource: dynamic: strict: false # 开发环境可关闭严格模式提高容错

4.2 常见错误示例

错误1:primary指定了不存在的数据源

spring: datasource: dynamic: primary: non_exist_db # 错误:配置中没有这个数据源

错误2:strict=true但缺少必要的@DS注解

public class UserService { // 没有@DS注解,strict=true时会尝试使用primary数据源 // 如果primary数据源也不存在就会抛异常 }

错误3:YAML格式缩进错误

spring: datasource: dynamic: primary: master # 错误:缩进不正确导致配置不生效

4.3 调试技巧

当遇到数据源问题时,可以:

  1. 开启debug日志:

    logging: level: com.baomidou.dynamic.datasource: debug
  2. 检查数据源初始化日志:

    DynamicDataSourceProvider - Loaded 2 datasources
  3. 验证数据源切换:

    @Test void testDataSourceSwitch() { // 验证默认数据源 String defaultDs = DynamicDataSourceContextHolder.peek(); assertEquals("master", defaultDs); // 验证注解切换 DynamicDataSourceContextHolder.push("slave"); assertEquals("slave", DynamicDataSourceContextHolder.peek()); }

5. 高级配置与原理深入

对于需要更精细控制数据源的项目,可以了解以下高级特性:

5.1 多数据源组支持

dynamic-datasource支持数据源分组,可以将多个物理数据源作为一个逻辑组使用:

spring: datasource: dynamic: primary: group1 # 使用数据源组作为默认 group1: # 数据源组定义 ds1: url: jdbc:mysql://localhost:3306/db1 ds2: url: jdbc:mysql://localhost:3306/db2

5.2 自定义数据源选择策略

通过实现DynamicDataSourceStrategy接口可以自定义数据源选择逻辑:

public class RandomDataSourceStrategy implements DynamicDataSourceStrategy { @Override public String determineDataSource( List<String> dataSourceKeys) { // 随机选择一个数据源 Random random = new Random(); return dataSourceKeys.get( random.nextInt(dataSourceKeys.size())); } }

然后在配置中指定策略:

spring: datasource: dynamic: strategy: com.example.RandomDataSourceStrategy

5.3 事务管理注意事项

在多数据源环境下,需要特别注意事务管理:

  1. 声明式事务

    @Transactional @DS("order_db") public void placeOrder(Order order) { // 跨数据源操作需要特别注意事务传播 }
  2. 编程式事务

    @Autowired private DataSourceTransactionManager transactionManager; public void batchProcess() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { // 业务逻辑 transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); throw e; } }

在实际项目中,我们遇到过这样一个案例:一个报表生成服务需要从多个业务库查询数据然后写入报表库。最初的设计是在每个DAO方法上添加@DS注解,但随着业务增长,这种方式变得难以维护。最终我们重构为使用AOP根据方法名自动路由数据源:

@Aspect @Component public class DataSourceRoutingAspect { @Before("execution(* com.example..*Repository.*(..))") public void beforeMethod(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); if (methodName.startsWith("find") || methodName.startsWith("get")) { DynamicDataSourceContextHolder.push("read_db"); } else { DynamicDataSourceContextHolder.push("write_db"); } } @After("execution(* com.example..*Repository.*(..))") public void afterMethod() { DynamicDataSourceContextHolder.poll(); } }

这种设计既保持了代码的简洁性,又能灵活地根据操作类型自动选择合适的数据源。

http://www.jsqmd.com/news/972562/

相关文章:

  • 模板即系统:文档自动化的核心原理与工程实践
  • 别再花钱了!电信悦ME IHO-3000高安版刷机固件资源整理与鉴别指南
  • Mythos门控能力:大模型可验证推理的工程实践指南
  • 机器学习模型生产化四条生命线:可观测性、可复现性、可扩展性、可治理性
  • 别再死磕有标签数据了!用MoCo和SimCLR玩转自监督对比学习,5分钟搞懂核心思想
  • 告别12位精度瓶颈:手把手教你用F28335 DSP驱动AD7606实现16位高精度数据采集
  • Matlab版SAR点目标RDA成像工具包:支持低斜视角与SRC2/SRC3大斜视角补偿
  • 2026年质量好的冠晶石仿石漆/建筑外墙仿石漆/别墅外墙仿石漆/农村自建房仿石漆生产厂家推荐 - 品牌宣传支持者
  • STM32上cJSON_PrintUnformatted返回NULL?别慌,八成是堆内存Heap_Size没给够
  • 硬件设计实战:10欧姆电阻如何解决热插拔浪涌导致的芯片损坏
  • 告别连接失败!手把手教你为Ubuntu上的Barrier生成并配置SSL证书(解决ssl certificate doesn‘t exist)
  • JMeter 5.6.2 一键启动压力测试环境(含全量依赖与多协议支持)
  • 信息论实战指南:用香农思维优化日常沟通与决策
  • 别再只盯着性能了!聊聊MTCMOS里那个‘偷懒’的睡眠晶体管是怎么省电的
  • 每日 AI 研究简报 · 2026-06-07
  • AU混响终极指南:从‘干声’到‘空间感’,用总音轨和发送技巧打造专业人声
  • LangGraph+Redis构建可回溯、可审计的AI代理系统
  • 用Python把文字或小图藏进照片里:基于RGB最低位的隐写工具
  • C语言代码考古神器:用cflow深度分析多文件项目,快速定位核心函数与依赖
  • 2026年靠谱的多节电动缸/江苏折返式电动缸厂家哪家好 - 行业平台推荐
  • LabWindows/CVI:电子工程师的GUI开发利器,C语言实现高效上位机
  • 从机器人到VR:用PCL点云库搞定3D数据处理,这份保姆级入门指南请收好
  • MATLAB vs Python:模糊控制实战,用洗衣机案例说透两者差异与选型
  • 从智能手表到电动汽车:拆解OTA差分升级背后的BSDiff算法与实战
  • Python 3.10安装后必做的5件事:从环境配置到写出你的第一个自动化脚本
  • 单片机PWM语音播放:ADPCM压缩与硬件滤波实战
  • 用MATLAB的LMgist工具箱5分钟搞定图像GIST特征提取(附完整代码)
  • MATLAB与Python双平台音频时频分析工具:STFT语谱图+小波能量分布可视化
  • 2026年靠谱的煤矿液压支架普阀/矿用液压支架阀/液压支架普阀/安徽矿用液压支架阀公司选择指南 - 品牌宣传支持者
  • 智能车竞赛避坑指南:如何用Apriltag实现稳定可靠的厘米级定位?