<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${dynamic.version}</version> </dependency> 简介 前两篇博客介绍了用基本的方式做多数据源,可以应对一般的情况,但是遇到一些复杂的情况就需要扩展下功能了,比如:动态增减数据源、数据源分组,纯粹多库 读写分离 一主多从、从其他数据库或者配置中心读取数据源等等。其实就算没有这些需求,使用这个实现多数据源也比之前使用AbstractRoutingDataSource要便捷的多 dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。 github: https://github.com/baomidou/dynamic-datasource-spring-boot-starter 文档: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/wiki 它跟mybatis-plus是一个生态圈里的,很容易集成mybatis-plus 特性: 数据源分组,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 内置敏感参数加密和启动初始化表结构schema数据库database。 提供对Druid,Mybatis-Plus,P6sy,Jndi的快速集成。 简化Druid和HikariCp配置,提供全局参数配置。 提供自定义数据源来源接口(默认使用yml或properties配置)。 提供项目启动后增减数据源方案。 提供Mybatis环境下的 纯读写分离 方案。 使用spel动态参数解析数据源,如从session,header或参数中获取数据源。(多租户架构神器) 提供多层数据源嵌套切换。(ServiceA >>> ServiceB >>> ServiceC,每个Service都是不同的数据源) 提供 不使用注解 而 使用 正则 或 spel 来切换数据源方案(实验性功能)。 基于seata的分布式事务支持。 ============================================================================================================== 核心配置类 DynamicDataSourceAutoConfiguration @Bean @ConditionalOnMissingBean public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) { DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); // 改造时自定义, 并覆盖核心方法 dataSource.setPrimary(properties.getPrimary()); dataSource.setStrategy(properties.getStrategy()); dataSource.setProvider(dynamicDataSourceProvider); dataSource.setP6spy(properties.getP6spy()); dataSource.setStrict(properties.getStrict()); return dataSource; } 抽象动态获取数据源 AbstractRoutingDataSource /** * 子类实现决定最终数据源 * * @return 数据源 */ protected abstract DataSource determineDataSource(); @Override public Connection getConnection() throws SQLException { return determineDataSource().getConnection(); } 核心动态数据源组件 DynamicRoutingDataSource /** * 所有数据库 */ private Map<String, DataSource> dataSourceMap = new LinkedHashMap<>(); /** * 分组数据库 */ private Map<String, DynamicGroupDataSource> groupDataSources = new ConcurrentHashMap<>(); @Override public DataSource determineDataSource() { return getDataSource(DynamicDataSourceContextHolder.peek()); } private DataSource determinePrimaryDataSource() { log.debug("从默认数据源中返回数据"); return groupDataSources.containsKey(primary) ? groupDataSources.get(primary).determineDataSource() : dataSourceMap.get(primary); } /** * 获取当前所有的数据源 * * @return 当前所有数据源 */ public Map<String, DataSource> getCurrentDataSources() { return dataSourceMap; } /** * 获取的当前所有的分组数据源 * * @return 当前所有的分组数据源 */ public Map<String, DynamicGroupDataSource> getCurrentGroupDataSources() { return groupDataSources; } /** * 获取数据源 * * @param ds 数据源名称 * @return 数据源 */ public DataSource getDataSource(String ds) { if (StringUtils.isEmpty(ds)) { return determinePrimaryDataSource(); } else if (!groupDataSources.isEmpty() && groupDataSources.containsKey(ds)) { log.debug("从 {} 组数据源中返回数据源", ds); return groupDataSources.get(ds).determineDataSource(); } else if (dataSourceMap.containsKey(ds)) { log.debug("从 {} 单数据源中返回数据源", ds); return dataSourceMap.get(ds); } if (strict) { throw new RuntimeException("不能找到名称为" + ds + "的数据源"); } return determinePrimaryDataSource(); } ===================================================================================================
如果有特殊业务, 例如多数据源事务控制(单个节点(分布式事务另当别论)), 可以参考以上核心代码加以改造, 简记....................以防忘记!!!!!!!!!