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. 灵活扩展
  • 可以轻松添加新的数据源

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

相关推荐
色空大师2 天前
【mybatisPlus详解】
java·mybatis·mybatisplus
Roye_ack3 天前
【黑马点评 - 实战篇01】Redis项目实战(Windows安装Redis6.2.6 + 发送验证码 + 短信验证码登录注册 + 拦截器链 - 登录校验)
数据库·spring boot·redis·缓存·mybatisplus·session·黑马点评
sniper_fandc10 天前
MybatisPlus和pagehelper分页冲突—关于jsqlparser、pagehelper、MybatisPlus三者的版本兼容问题
mybatis·mybatisplus
sniper_fandc11 天前
关于Mybatis-Plus的insertOrUpdate()方法使用时的问题与解决—数值精度转化问题
java·前端·数据库·mybatisplus·主键id
Mr.朱鹏1 个月前
ShardingJDBC实战指南
java·jvm·数据库·spring·分库分表·shardingjdbc·shardingshere
77qqqiqi2 个月前
解决Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required报错问题
java·数据库·微服务·mybatis·mybatisplus
77qqqiqi3 个月前
mp核心功能
java·数据库·微服务·mybatisplus
她说..3 个月前
MybatisPlus-快速入门
java·spring boot·spring cloud·微服务·mybatis·mybatisplus
一叶飘零_sweeeet3 个月前
从基础到进阶:MyBatis-Plus 分页查询封神指南
java·mybatisplus