news 2026/4/25 6:01:12

ShardingSphere系列04:MybatisPlus动态数据源与ShardingJdbc分表策略的深度整合实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ShardingSphere系列04:MybatisPlus动态数据源与ShardingJdbc分表策略的深度整合实践

1. 为什么需要整合动态数据源与分表策略

在实际业务开发中,我们经常会遇到两个典型场景:一是需要根据业务模块访问不同的数据库(多数据源),二是单个数据表数据量过大需要分表存储(分库分表)。MybatisPlus的动态数据源和ShardingJdbc分别擅长解决这两个问题,但将它们整合在一起使用时却会遇到不少坑。

我最近在一个电商项目中就遇到了这样的需求:订单数据需要按用户ID分表存储,同时又要能灵活切换到日志库、商品库等其他数据源。刚开始尝试时,发现直接用MybatisPlus的@DS注解切换数据源会导致ShardingJdbc的分表规则失效,反之亦然。经过多次调试才找到正确的整合方式。

这种整合的核心价值在于:

  • 业务代码无需关心底层是单表还是分表
  • 可以透明地使用@DS注解切换不同业务数据源
  • 分表策略对上层完全透明,就像操作单表一样简单

2. 环境准备与依赖配置

2.1 基础环境搭建

首先确保你的Spring Boot项目版本在2.3.x以上,我这里用的是2.7.12版本。数据库准备两个实例:

  • 主库:table_sharding(用于订单分表)
  • 从库:product_db(模拟商品数据)

创建订单表结构(分4个表):

CREATE TABLE `order_info_0` ( `id` bigint NOT NULL, `user_id` bigint NOT NULL, `product_id` bigint DEFAULT NULL, `amount` decimal(10,2) DEFAULT NULL, `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

记得同时创建order_info_1到order_info_3共4个相同结构的表。

2.2 关键依赖管理

pom.xml中需要特别注意这些依赖的版本兼容性:

<!-- MybatisPlus核心 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!-- 动态数据源 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency> <!-- ShardingSphere --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version>5.3.2</version> </dependency> <!-- 数据源驱动 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.16</version> </dependency>

特别提醒:ShardingSphere 5.x版本与MybatisPlus 3.5+存在一些SPI加载冲突,需要额外添加以下配置类:

@Configuration public class ShardingConfig { @PostConstruct void init() { System.setProperty("org.apache.shardingsphere.sql.parser.sql.cache.enabled", "false"); } }

3. 核心配置实战

3.1 动态数据源桥接配置

这是整个整合最关键的环节,我们需要创建一个DataSourceConfiguration来桥接两者:

@Configuration @AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class}) public class DataSourceConfig { private static final String SHARDING_DS_NAME = "sharding"; @Autowired private DynamicDataSourceProperties properties; @Lazy @Resource private DataSource shardingDataSource; @Bean public DynamicDataSourceProvider dynamicDataSourceProvider() { return new AbstractDataSourceProvider() { @Override public Map<String, DataSource> loadDataSources() { Map<String, DataSource> dataSourceMap = createDataSourceMap(properties.getDatasource()); // 将ShardingSphere管理的数据源纳入动态数据源体系 dataSourceMap.put(SHARDING_DS_NAME, shardingDataSource); return dataSourceMap; } }; } @Primary @Bean public DataSource dataSource() { DynamicRoutingDataSource ds = new DynamicRoutingDataSource(); ds.setPrimary(properties.getPrimary()); ds.setProvider(dynamicDataSourceProvider()); return ds; } }

这个配置类做了三件重要的事情:

  1. 加载MybatisPlus动态数据源的常规配置
  2. 获取ShardingSphere创建的分片数据源
  3. 将分片数据源注册为动态数据源的一个特殊数据源

3.2 YAML配置详解

application.yml需要分层配置:

spring: shardingsphere: datasource: names: sharding sharding: type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/table_sharding username: root password: 123456 rules: sharding: tables: order_info: actual-data-nodes: sharding.order_info_$->{0..3} table-strategy: standard: sharding-column: user_id precise-algorithm-class-name: com.example.config.OrderShardingAlgorithm key-generators: snowflake: type: SNOWFLAKE datasource: dynamic: primary: master datasource: master: url: jdbc:mysql://localhost:3306/product_db username: root password: 123456 log: url: jdbc:mysql://192.168.1.100:3306/log_db username: log_user password: log@123

注意几个关键点:

  1. ShardingSphere的数据源名称必须与桥接配置中的SHARDING_DS_NAME一致
  2. 动态数据源的primary设置会影响@DS注解的默认行为
  3. 分片算法建议使用自定义类实现更灵活的分片逻辑

4. 业务层实现技巧

4.1 实体与Mapper设计

对于分表实体,需要特别注意两点:

@Data @TableName("order_info") // 逻辑表名 public class OrderInfo { @TableId(type = IdType.ASSIGN_ID) private Long id; private Long userId; // 分片键 private Long productId; private BigDecimal amount; private Date createTime; }

Mapper接口保持常规写法即可:

@Mapper public interface OrderMapper extends BaseMapper<OrderInfo> { @DS("sharding") List<OrderInfo> selectByUser(@Param("userId") Long userId); }

4.2 服务层的最佳实践

在Service层使用时,推荐这种写法:

@Service public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> { // 分表操作统一使用sharding数据源 @DS("sharding") public void processOrder(OrderInfo order) { save(order); // 会自动根据userId分片 // 切换到商品库查询 Product product = productService.getById(order.getProductId()); } // 多数据源混合操作 public void fullProcess(OrderInfo order) { // 默认使用master数据源 logService.record(order); // 切换到分片数据源 processOrder(order); } }

4.3 自定义分片算法示例

对于复杂分片逻辑,建议实现标准分片算法:

public class OrderShardingAlgorithm implements StandardShardingAlgorithm<Long> { @Override public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) { // 按userId的哈希值取模分片 int size = availableTargetNames.size(); long mod = shardingValue.getValue() % size; return "order_info_" + Math.abs(mod); } }

5. 常见问题排查指南

5.1 典型错误与解决方案

问题一:分表规则不生效现象:数据总是插入到第一个物理表 排查步骤:

  1. 检查sharding-column是否与实体字段一致
  2. 确认分片算法返回的表名后缀在actual-data-nodes范围内
  3. 在yaml中添加sql-show: true查看实际路由

问题二:动态切换失效现象:@DS注解切换后仍使用默认数据源 解决方案:

  1. 检查DataSourceConfiguration是否加了@Primary
  2. 确认没有在多个地方重复创建DataSource bean
  3. 在启动日志中搜索"DynamicDataSource"确认初始化顺序

5.3 性能优化建议

  1. 分片键选择:尽量选择离散度高的字段,避免热点问题
  2. 连接池配置:建议为分片数据源设置更大的maxPoolSize
  3. 批量操作:使用ShardingSphere提供的批量插入API提升性能
  4. 分布式事务:对于跨分片操作,考虑使用Seata集成

我在实际项目中还发现一个有用的技巧:对于需要频繁跨库查询的场景,可以创建一个视图数据库,通过ETL工具定期同步需要关联查询的数据,这样既能保持分片的优势,又能解决关联查询的性能问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 5:57:07

Python数据类型及常用方法

一 引入我们学习变量是为了让计算机能够像人一样去记忆事物的某种状态&#xff0c;而变量的值就是用来存储事物状态的&#xff0c;很明显事物的状态分成不同种类的&#xff08;比如人的年龄&#xff0c;身高&#xff0c;职位&#xff0c;工资等等&#xff09;&#xff0c;所以变…

作者头像 李华
网站建设 2026/4/25 5:55:59

AI查看文档001

#!/usr/bin/env bash set -euo pipefail# # Ceph CRUSH Root Usage Monitor # 功能: 自动发现集群所有不同的 take_root&#xff0c;每个 root 只处理一次&#xff08;去重&#xff09; # - 指标写入 textfile collector 目录&#xff08;供 node_exporter 采集&#xf…

作者头像 李华
网站建设 2026/4/25 5:50:18

量子霸权验证白皮书:软件测试从业者的专业视角与应对框架

当计算范式转移&#xff0c;测试的疆域被重塑我们正站在一场计算革命的临界点上。“量子霸权”或“量子优越性”概念的提出&#xff0c;标志着量子设备在特定任务上的性能已开始超越最强大的经典超级计算机。从理论构想迈向工程现实&#xff0c;这一进程不仅重新定义了计算的极…

作者头像 李华