ShardingJDBC整合MybatisPlus的动态数据源

依赖

XML 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.6.RELEASE</version>
</parent>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>4.2.0</version>
</dependency>

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency>

dynamic-datasource-spring-boot-starter 版本3.1.0 有BUG,异常情况下切换数据源会不成功,导致找不到表,所以使用 4.2.0

配置

Bash 复制代码
spring.shardingsphere.sharding.default-data-source-name = ds
# 数据源配置
spring.shardingsphere.datasource.names = ds

# 数据源具体配置
spring.shardingsphere.datasource.ds.type = com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds.driver-class-name = com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds.jdbc-url = jdbc:mysql://xxxxxxxxxxxxxx:3306/aep?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
spring.shardingsphere.datasource.ds.username = root
spring.shardingsphere.datasource.ds.password = pppppppppppp

# 分表配置 - 表名称
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.actual-data-nodes = ds.aep_abtest_config_deploy_log_$->{2025..2035}0$->{1..9},ds.aep_abtest_config_deploy_log_$->{2025..2035}1$->{0..2}

# 分表策略 - 分片列
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.table-strategy.standard.sharding-column = create_time

# 分表策略 - 精确分片算法类
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.table-strategy.standard.precise-algorithm-class-name = com.transsnet.aep.configuration.MonthlyShardingAlgorithm

# 主键生成策略 - 列名
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.key-generator.column = id

# 主键生成策略 - 类型
spring.shardingsphere.sharding.tables.aep_abtest_config_deploy_log.key-generator.type = SNOWFLAKE

# 显示SQL
spring.shardingsphere.props.sql.show = true


# 是否开启ShardingSphere
spring.shardingsphere.enabled = true

# 数据源连接池配置
spring.shardingsphere.datasource.ds.connection-timeout = 30000
spring.shardingsphere.datasource.ds.idle-timeout = 600000
spring.shardingsphere.datasource.ds.max-lifetime = 1800000
spring.shardingsphere.datasource.ds.maximum-pool-size = 10
spring.shardingsphere.datasource.ds.minimum-idle = 5
spring.shardingsphere.datasource.ds.pool-name = HikariPool-ds

# 默认使用分片数据源
spring.datasource.dynamic.primary = sharding


spring.datasource.dynamic.datasource.ups.poolName = ups-pool
spring.datasource.dynamic.datasource.ups.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.ups.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.dynamic.datasource.ups.url = jdbc:mysql://xxxxxxxxxxxxxx:3306/ups?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true
spring.datasource.dynamic.datasource.ups.username = root
spring.datasource.dynamic.datasource.ups.password = pppppppppppp


spring.datasource.dynamic.datasource.dim.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.dim.poolName = dim-pool
spring.datasource.dynamic.datasource.dim.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.dynamic.datasource.dim.url = jdbc:mysql://xxxxxxxxxxxxxx:3306/ups_dim?characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false
spring.datasource.dynamic.datasource.dim.username = root
spring.datasource.dynamic.datasource.dim.password = pppppppppppp

代码配置

DynamicDataSourceConfig 类是一个关键的数据源集成配置类,它负责将 ShardingSphere 的分片数据源与 dynamic-datasource 的多数据源动态路由功能进行整合。

核心目标:让 ShardingSphere 的分片数据源能够作为 dynamic-datasource 框架中的一个普通数据源来使用,实现分片数据源和非分片数据源的统一管理。

Java 复制代码
package com.transsnet.aep.configuration;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

@Configuration
@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
public class DynamicDataSourceConfig {

    @Resource
    private DynamicDataSourceProperties properties;

    /**
     * 未使用分片, 脱敏的名称(默认): shardingDataSource
     * shardingjdbc使用了主从: masterSlaveDataSource
     * 此处如果主从策略配置在sharding属性下面,需要使用shardingDataSource
     */
    @Lazy
    @Resource(name = "shardingDataSource")
    private DataSource shardingDataSource;

    @Resource
    private DefaultDataSourceCreator dataSourceCreator;

    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        return new AbstractDataSourceProvider(dataSourceCreator) {
            @Override
            public Map<String, DataSource> loadDataSources() {
                // 先创建动态数据源
                Map<String, DataSource> dataSourceMap = createDataSourceMap(properties.getDatasource());
                // 确保动态数据源不为空
                if (dataSourceMap.isEmpty()) {
                    dataSourceMap = Maps.newHashMap();
                }
                // 将ShardingSphere数据源添加到动态数据源集合中
                dataSourceMap.put("sharding", shardingDataSource);
                return dataSourceMap;
            }
        };
    }

    /**
     * 将动态数据源设置为首选的
     * 当spring存在多个数据源时, 自动注入的是首选的对象
     * 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
     */
    @Primary
    @Bean
    public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
        List<DynamicDataSourceProvider> providers = Lists.newArrayList(dynamicDataSourceProvider);
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
        dataSource.setPrimary(properties.getPrimary());
        dataSource.setStrict(properties.getStrict());
        dataSource.setStrategy(properties.getStrategy());
        dataSource.setP6spy(properties.getP6spy());
        dataSource.setSeata(properties.getSeata());
        return dataSource;
    }
}

这个 DynamicDataSourceConfig 类是一个桥梁类,它:

  1. 集成:将 ShardingSphere 的分片能力集成到 dynamic-datasource 框架中

  2. 统一:提供统一的数据源访问接口

  3. 隔离:确保分片数据源和非分片数据源相互隔离

  4. 灵活:支持通过注解动态切换数据源

启动类

TypeScript 复制代码
@ComponentScan(basePackages = {"com.transsnet"})
@MapperScan(basePackages = {"com.transsnet.aep.mapper"})
// 防止Spring Boot的自动配置与ShardingSphere、dynamic-datasource的配置发生冲突
@SpringBootApplication(exclude = {
        DataSourceAutoConfiguration.class,
        DataSourcePoolMetricsAutoConfiguration.class
})
public class AepWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(AepWebApplication.class, args);
    }

}

启动类中排除这些自动配置类是为了防止Spring Boot的自动配置与ShardingSphere、dynamic-datasource的配置发生冲突。让我详细解释每个排除项的作用:

1. DataSourceAutoConfiguration.class
为什么要排除:

java

exclude = DataSourceAutoConfiguration.class

作用:
  • 防止自动创建数据源:Spring Boot会自动根据spring.datasource.*配置创建默认数据源

  • 避免配置冲突:我们使用ShardingSphere和dynamic-datasource来管理数据源,不需要Spring Boot的自动配置

  • 防止Bean重复:避免创建多个相同类型的数据源Bean导致冲突

如果不排除:

Spring Boot会尝试根据以下配置创建数据源:

properties

spring.datasource.url=...spring.datasource.username=...spring.datasource.password=...

这与我们手动配置的ShardingSphere数据源冲突。

2. DataSourcePoolMetricsAutoConfiguration.class
为什么要排除:

java

exclude = DataSourcePoolMetricsAutoConfiguration.class

作用:
  • 避免监控指标冲突:这个自动配置会为数据源创建监控指标

  • 防止Bean依赖问题:它期望找到Spring Boot自动创建的数据源,但我们使用的是自定义数据源

  • 指标重复:ShardingSphere和dynamic-datasource可能有自己的监控机制

总结

1. 数据源隔离
  • 分片数据源和非分片数据源完全隔离

  • 避免分片逻辑影响到普通业务表

2. 统一管理
  • 通过统一的 @DS 注解来切换数据源

  • 简化代码,提高可维护性

3. 灵活扩展
  • 可以轻松添加新的数据源

  • 分片和非分片数据源可以独立演进

相关推荐
LSL666_7 天前
mybatisplus入门案例
数据库·mysql·mybatisplus
fanruitian8 天前
springboot-mybatisplus-demo
spring boot·后端·mybatis·mybatisplus
草原印象14 天前
Spring Boot Spring MVC MyBatis MyBatis Plus框架编写项目实战案例
spring boot·spring·mybatis·springmvc·mybatisplus
tgethe15 天前
MybatisPlus基础部分详解(中篇)
java·spring boot·mybatisplus
tgethe15 天前
MybatisPlus基础部分详解(上篇)
java·spring boot·mybatisplus
tgethe15 天前
MybatisPlus基础部分详解(下篇)
java·spring boot·mybatisplus
色空大师2 个月前
【mybatisPlus详解】
java·mybatis·mybatisplus
Roye_ack2 个月前
【黑马点评 - 实战篇01】Redis项目实战(Windows安装Redis6.2.6 + 发送验证码 + 短信验证码登录注册 + 拦截器链 - 登录校验)
数据库·spring boot·redis·缓存·mybatisplus·session·黑马点评
sniper_fandc2 个月前
MybatisPlus和pagehelper分页冲突—关于jsqlparser、pagehelper、MybatisPlus三者的版本兼容问题
mybatis·mybatisplus