简介:本资源是一个基于SpringBoot、ShardingJDBC与MyBatis的轻量级分库分表实战项目,面向Java中高级开发者及分布式系统学习者,聚焦高并发场景下数据库水平扩展的核心痛点。项目完整呈现了从数据源配置、分片策略定义(如用户ID哈希取模)、MyBatis动态SQL适配到多数据源透明访问的全流程实现,具备即学即用的工程参考价值。压缩包共15个文件,含5个核心Java类(涵盖配置类、实体、Mapper与Service)、2个XML映射文件、1个application.yaml分片配置、1个SQL建表脚本、1个README.md说明文档及构建相关文件(mvnw、mvnw.cmd、pom.xml等),整体仅61KB,结构精炼、无冗余依赖。目前已有188人学习下载,读者可直接导入IDE运行验证分片路由逻辑,快速掌握ShardingJDBC在SpringBoot生态中的集成要点、配置规范与典型问题应对思路。
1. 分库分表不是加个注解就完事:一个 Spring Boot + ShardingSphere-JDBC + MyBatis 的真实落地项目,专治高并发下 MySQL 单库写入瓶颈
你有没有遇到过这样的场景:订单服务上线三个月,QPS 还没破 200,数据库连接池就开始疯狂报Connection is closed;慢 SQL 告警每天 37 条,其中 29 条都卡在SELECT * FROM order_info WHERE user_id = ?;DBA 拿着监控图找你谈话,说“这张表再不拆,下个月主从延迟要上 30 秒”。这不是理论题,是某电商中台团队的真实血泪现场。这个springboot_shardingjdbc_mybatis项目,就是他们用两周时间从零搭起、跑通全链路、压测稳定支撑 5000+ TPS 的最小可行分库分表工程——它不讲 CAP 理论,不画六层架构图,只给你能git clone && mvn clean package && java -jar跑起来的代码,包含完整的分片键路由逻辑、跨库 JOIN 的妥协方案、分页查询的深坑修复、以及 MyBatis 层如何与 ShardingSphere-JDBC 无感协同。如果你正被单表千万级数据、月增 200W 订单、或sharding-jdbc-spring-boot-starter配置项看晕,这个项目就是你的第一块调试板。
2. 工程结构与技术栈:Spring Boot 2.7.x 为底座,ShardingSphere-JDBC 5.3.2 是分片引擎,MyBatis-Plus 3.5.3 提供 CRUD 加速
这个项目不是玩具 Demo,而是按生产环境标准组织的 Maven 多模块结构。它没有用 ShardingSphere-Proxy(那是 DBA 的事),也没上 Seata(事务暂未跨分片),所有分片逻辑全部下沉到应用层——这意味着你能直接看到每条 SQL 是怎么被重写的、分片键值是怎么被提取的、路由结果是怎么被缓存的。技术选型不是拍脑袋:Spring Boot 2.7.x 是为了兼容 JDK 8 且避开 Spring Boot 3 的 Jakarta EE 9 迁移成本;ShardingSphere-JDBC 5.3.2 是当前 5.x 系列最稳定的 GA 版,对INSERT ... SELECT和ORDER BY LIMIT的改写逻辑已收敛;MyBatis-Plus 3.5.3 则提供了LambdaQueryWrapper和自动填充功能,让分片字段(如user_id)的赋值不再靠手写@TableField(fill = FieldFill.INSERT)注解硬编码。
2.1 项目模块划分:四个子模块各司其职,拒绝大杂烩式单体
整个工程采用清晰的分层模块设计,每个模块职责单一,可独立编译、测试、部署:
sharding-demo-api:Spring Boot Web 启动模块,含 Controller、全局异常处理器、Swagger 文档配置;sharding-demo-service:业务逻辑层,封装了订单创建、用户分页查询、跨库统计等核心用例;sharding-demo-dao:数据访问层,仅包含 MyBatis Mapper 接口和 XML 映射文件,不包含任何分片逻辑;sharding-demo-common:公共模块,定义实体类(OrderEntity)、分片策略配置类(ShardingConfig)、以及自定义的ShardingKeyHolder(用于获取分片键值)。
提示:这种拆分不是为了炫技。当你要把
order_info表从 2 库 4 表扩到 4 库 8 表时,你只需要改sharding-demo-common里的分片算法配置,sharding-demo-dao和sharding-demo-service完全不用动——这是模块隔离带来的真实可维护性。
2.2 核心依赖版本锁定:pom.xml 中的关键 dependencyManagement 片段
项目在父 POM 的<dependencyManagement>中严格锁定了所有关键组件版本,避免因传递依赖引发的NoSuchMethodError或分片失效。以下是必须关注的三组依赖:
<!-- Spring Boot BOM --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.7.18</version> <type>pom</type> <scope>import</scope> </dependency> <!-- ShardingSphere-JDBC BOM --> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-bom</artifactId> <version>5.3.2</version> <type>pom</type> <scope>import</scope> </dependency> <!-- MyBatis-Plus BOM --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-bom</artifactId> <version>3.5.3.1</version> <type>pom</type> <scope>import</scope> </dependency>注意:shardingsphere-jdbc-bom必须显式引入,否则shardingsphere-jdbc-core-spring-boot-starter可能拉取到 5.2.x 的旧版,导致StandardShardingAlgorithm接口方法签名不匹配(这是踩过的坑,后面会细说)。
2.3 数据源与分片规则配置:application.yml 中的 12 行核心配置
分片不是靠魔法生效的,所有路由规则都明文写在application.yml里。本项目采用分库不分表策略(即db_0,db_1两个物理库,每个库内order_info表不拆分),分片键为user_id,使用ModShardingAlgorithm取模路由。以下是精简后的核心配置(已去除 HikariCP 连接池细节):
spring: shardingsphere: props: sql-show: true # 开发期必开,看SQL重写效果 datasource: names: db_0,db_1 db_0: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db_0?useSSL=false&serverTimezone=UTC username: root password: root db_1: driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/db_1?useSSL=false&serverTimezone=UTC username: root password: root rules: - !SHARDING tables: order_info: actual-data-nodes: db_${0..1}.order_info database-strategy: standard: sharding-column: user_id sharding-algorithm-name: db_mod sharding-algorithms: db_mod: type: MOD props: sharding-count: 2这段配置的含义是:所有对order_info表的操作,ShardingSphere-JDBC 会根据user_id的值对 2 取模,结果为 0 路由到db_0,为 1 路由到db_1。actual-data-nodes: db_${0..1}.order_info是 SpEL 表达式,生成db_0.order_info和db_1.order_info两个逻辑节点。
2.4 实体类与 Mapper 接口:MyBatis 层完全无感,像写单库一样写代码
这是本项目最值得称道的设计点:DAO 层代码与单库项目完全一致,没有任何 ShardingSphere 相关注解或接口。OrderEntity就是一个普通 POJO:
@Data @TableName("order_info") public class OrderEntity { @TableId(type = IdType.ASSIGN_ID) private Long id; private Long userId; // 分片键,必须有 getter/setter private String orderNo; private BigDecimal amount; private LocalDateTime createTime; }对应的 Mapper 接口也毫无特殊:
@Mapper public interface OrderMapper extends BaseMapper<OrderEntity> { // 自定义方法也支持分片 List<OrderEntity> selectByUserId(@Param("userId") Long userId); }XML 文件中写的是标准 SQL:
<select id="selectByUserId" resultType="com.example.entity.OrderEntity"> SELECT * FROM order_info WHERE user_id = #{userId} </select>ShardingSphere-JDBC 在 JDBC Driver 层拦截了PreparedStatement,自动将SELECT * FROM order_info WHERE user_id = ?改写为SELECT * FROM order_info WHERE user_id = ?并路由到对应库——对 MyBatis 来说,它只知道自己执行了一条 SQL,根本不知道背后发生了什么。这种透明性,是开发者敢在生产环境用它的底气。
3. 分片策略实现:从 Mod 算法到自定义复合分片,看懂StandardShardingAlgorithm如何决定路由
分片策略是整个项目的灵魂。ShardingSphere-JDBC 提供了StandardShardingAlgorithm(标准分片)、ComplexKeysShardingAlgorithm(复合分片)、HintShardingAlgorithm(强制路由)三种接口。本项目实现了前两种,并在sharding-demo-common模块中封装为可复用的 Bean。理解它们,你就掌握了分片的主动权。
3.1 标准分片算法:ModShardingAlgorithm的完整实现与参数说明
ModShardingAlgorithm是 ShardingSphere 内置的取模算法,但项目中我们并未直接使用type: MOD,而是手写了一个可调试、可打日志的实现类,放在com.example.sharding.algorithm包下:
@Component("dbModAlgorithm") public class DbModShardingAlgorithm implements StandardShardingAlgorithm<Long> { private int shardingCount = 2; @Override public void init(Properties props) { // 从配置文件读取 sharding-count,支持运行时调整 String count = props.getProperty("sharding-count"); if (StringUtils.isNotBlank(count)) { this.shardingCount = Integer.parseInt(count); } } @Override public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) { Long value = shardingValue.getValue(); int targetIndex = Math.abs(value.hashCode()) % shardingCount; // 日志记录路由决策,线上可关闭 log.info("Sharding user_id={} to db index={}, available: {}", value, targetIndex, availableTargetNames); return availableTargetNames.stream() .sorted() // 确保顺序一致,避免因 Set 无序导致路由不稳 .skip(targetIndex) .findFirst() .orElseThrow(() -> new RuntimeException("No available data source for " + value)); } @Override public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) { // 范围查询(如 BETWEEN)时,需返回所有可能命中的库名 return availableTargetNames; } @Override public String getType() { return "DB_MOD"; } }关键点解析:
init(Properties)方法读取配置中的sharding-count,允许你在不停机的情况下修改分片数(需配合数据库扩容);doSharding(PreciseShardingValue)处理等值查询(WHERE user_id = ?),Math.abs(value.hashCode()) % shardingCount是防负数取模的经典写法;doSharding(RangeShardingValue)处理范围查询(WHERE user_id BETWEEN ? AND ?),这里简单返回全部库名,意味着该查询会广播到所有库——这是性能妥协,但保证了结果正确性;@Component("dbModAlgorithm")的 Bean 名必须与application.yml中sharding-algorithm-name: db_mod对应,否则启动报错Cannot find sharding algorithm.
3.2 复合分片算法:当user_id和order_time联合决定路由时
业务发展后,单纯按user_id分库会出现热点问题(比如某大 V 用户一天下单 10W+)。这时需要引入二级分片键order_time,实现user_id % 2分库 +order_time / 86400 % 4分表(本项目演示分库逻辑)。复合分片需实现ComplexKeysShardingAlgorithm:
@Component("complexAlgorithm") public class ComplexShardingAlgorithm implements ComplexKeysShardingAlgorithm { @Override public Map<String, Collection<String>> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<?> shardingValues) { // 获取所有分片键值 Collection<Comparable<?>> userIds = shardingValues.getColumnNameAndShardingValuesMap().get("user_id"); Collection<Comparable<?>> orderTimes = shardingValues.getColumnNameAndShardingValuesMap().get("order_time"); Map<String, Collection<String>> result = new HashMap<>(); for (String each : availableTargetNames) { result.put(each, new ArrayList<>()); } // 简化逻辑:先按 user_id 分库,再在库内按 order_time 分表(此处只做分库示意) if (userIds != null && !userIds.isEmpty()) { Comparable<?> firstUserId = userIds.iterator().next(); int dbIndex = Math.abs(firstUserId.hashCode()) % 2; String targetDb = "db_" + dbIndex; result.get(targetDb).add("order_info"); // 表名固定 } return result; } @Override public String getType() { return "COMPLEX"; } }注意:复合分片在
application.yml中的配置方式不同,需指定sharding-columns: user_id,order_time,且 SQL 中必须同时出现这两个字段的条件,否则降级为全库路由。
3.3 分片键值提取机制:为什么user_id字段必须有 getter,且不能是驼峰?
这是新手最容易翻车的点。ShardingSphere-JDBC 在执行 SQL 前,会通过反射调用OrderEntity.getUserId()获取分片键值。如果:
userId字段是private Long userId;但没有getUserId()方法 → 启动时报Can't find getter method for sharding column 'user_id';- 实体类用了 Lombok 的
@Data,但userId字段名是userId,而数据库列名是user_id→ ShardingSphere 默认按 Java 字段名匹配,不会自动转下划线,所以sharding-column: user_id配置无效,必须改为sharding-column: userId; userId是Long类型,但插入时传了null→doSharding中value.hashCode()抛NullPointerException,需在算法中加空值判断。
解决方案:在DbModShardingAlgorithm.doSharding开头加防御:
if (value == null) { log.warn("Sharding column user_id is null, routing to default db_0"); return "db_0"; }4. 关键场景实战:跨库分页、分布式主键、读写分离配置,一个都不能少
分库分表后,很多单库习以为常的操作会突然失效。本项目完整覆盖了四大高频痛点场景,并给出可落地的解决方案。每一处都经过本地 H2 数据库模拟和 MySQL 真实环境验证。
4.1 跨库分页:LIMIT 10,20怎么不出错?用Stream+PageHelper的组合拳
分库后,SELECT * FROM order_info ORDER BY create_time DESC LIMIT 10,20这种语句会被路由到所有库,每个库返回自己的 20 条,ShardingSphere-JDBC 再合并去重——结果是错的,且性能极差。本项目采用内存聚合分页方案,在sharding-demo-service中封装了ShardingPageHelper工具类:
public class ShardingPageHelper { public static <T> PageResult<T> paginate(List<T> allData, int pageNum, int pageSize) { int fromIndex = (pageNum - 1) * pageSize; int toIndex = Math.min(fromIndex + pageSize, allData.size()); List<T> pageData = (fromIndex >= allData.size()) ? Collections.emptyList() : allData.subList(fromIndex, toIndex); return PageResult.<T>builder() .list(pageData) .pageNum(pageNum) .pageSize(pageSize) .total(allData.size()) .pages((int) Math.ceil((double) allData.size() / pageSize)) .build(); } }Controller 层调用方式:
@GetMapping("/orders/page") public Result<PageResult<OrderEntity>> listOrdersByPage(@RequestParam Long userId, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { // 先查出该用户所有订单(路由精准,无跨库) List<OrderEntity> allOrders = orderService.listByUserId(userId); // 再内存分页 PageResult<OrderEntity> pageResult = ShardingPageHelper.paginate(allOrders, pageNum, pageSize); return Result.success(pageResult); }提示:此方案适用于单用户数据量不超 10W 条的场景。若用户订单超百万,需改用
ES + MySQL架构,本项目不展开。
4.2 分布式主键:雪花算法SnowflakeKeyGenerateAlgorithm的定制化改造
ShardingSphere 内置的雪花算法生成的 ID 是Long型,但某些老系统要求String型主键。项目中我们继承SnowflakeKeyGenerateAlgorithm,重写generateKey()方法:
@Component("stringSnowflake") public class StringSnowflakeKeyGenerateAlgorithm extends SnowflakeKeyGenerateAlgorithm { @Override public Comparable<?> generateKey() { Long key = (Long) super.generateKey(); // 转为 19 位字符串,补零对齐(兼容旧系统) return String.format("%019d", key); } }在OrderEntity中声明:
@TableId(type = IdType.NONE, value = "id") private String id; // 注意这里是 Stringapplication.yml中配置:
spring: shardingsphere: rules: - !KEY_GENERATE column: id key-generator-name: string_snowflake key-generators: string_snowflake: type: STRING_SNOWFLAKE这样生成的主键形如"0000000001234567890",既满足分布式唯一,又兼容字符串主键的老系统。
4.3 读写分离配置:一主两从,master-slave规则如何与分片共存
本项目支持分片 + 读写分离嵌套。在application.yml中,先定义读写分离数据源,再将其作为分片的底层数据源:
spring: shardingsphere: datasource: names: master_ds,slave_ds_0,slave_ds_1 master_ds: # 主库配置 slave_ds_0: # 从库0配置 slave_ds_1: # 从库1配置 rules: - !READWRITE_SPLITTING dataSources: pr_ds: writeDataSourceName: master_ds readDataSourceNames: [slave_ds_0, slave_ds_1] - !SHARDING tables: order_info: actual-data-nodes: pr_ds.order_info # 注意:这里指向读写分离逻辑库 database-strategy: standard: sharding-column: user_id sharding-algorithm-name: db_mod关键点:actual-data-nodes: pr_ds.order_info中的pr_ds是读写分离逻辑库名,ShardingSphere-JDBC 会先路由到pr_ds,再由pr_ds内部根据SELECT/INSERT类型决定走主还是从——两层路由无缝衔接。
4.4 分布式事务兜底:LOCAL事务 + 最终一致性补偿
项目未引入 Seata,因为当前业务场景(订单创建)的事务边界明确:insert into order_info和update user_account不在同库,无法强一致。我们采用本地事务 + 异步消息补偿:
OrderService.createOrder()方法内,只对order_info表执行INSERT,用@Transactional保证单库事务;- 插入成功后,发一条 RocketMQ 消息到
account-change-topic; - 另一个消费服务监听该 Topic,执行
user_account扣款,失败则重试 3 次,再失败进死信队列人工干预。
这种模式在sharding-demo-service的OrderServiceImpl中有完整实现,包括消息发送失败的降级日志记录。
5. 避坑指南:5 个真实踩过的坑,每一条都来自凌晨三点的线上告警
别信网上那些“配置完就能跑”的教程。这个项目是在解决真实线上问题的过程中迭代出来的,以下 5 个坑,每一个都曾导致服务不可用或数据错乱。我把现象、原因、解决方案都写清楚,帮你省下至少两天排查时间。
5.1 现象:应用启动报java.lang.NoClassDefFoundError: org/apache/shardingsphere/infrastructure/merge/MergeEngine
原因:shardingsphere-jdbc-core-spring-boot-starter5.3.2 依赖了shardingsphere-infrastructure-merge模块,但该模块在 Maven 仓库中被标记为optional=true,导致部分构建工具(如 Gradle 6.x)未拉取。
解决:在pom.xml中显式添加该依赖:
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-infrastructure-merge</artifactId> <version>5.3.2</version> </dependency>5.2 现象:SELECT * FROM order_info WHERE user_id IN (1,2,3)查询结果为空,但单库执行正常
原因:IN查询在 ShardingSphere-JDBC 中默认使用ComplexKeysShardingAlgorithm,而项目中只配置了StandardShardingAlgorithm,导致路由失败,返回空集合。
解决:在application.yml的分片规则中,为IN查询显式指定算法类型:
database-strategy: standard: sharding-column: user_id sharding-algorithm-name: db_mod # 添加 complex 策略处理 IN complex: sharding-columns: user_id sharding-algorithm-name: db_mod5.3 现象:PageHelper.startPage(1,10)分页插件失效,返回全量数据
原因:PageHelper是基于 MyBatis 的Interceptor实现的,而 ShardingSphere-JDBC 的ShardingSphereDataSource会包装原始DataSource,导致PageHelper的ThreadLocal分页参数在 ShardingSphere 的执行链路中丢失。
解决:弃用PageHelper,改用项目内置的ShardingPageHelper(见 4.1 节),或在ShardingSphereDataSource初始化后,手动注册PageInterceptor:
@Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // 手动添加 PageInterceptor bean.setPlugins(new Interceptor[]{new PageInterceptor()}); return bean.getObject(); }5.4 现象:UPDATE order_info SET amount = ? WHERE id = ?更新语句路由到错误库,数据更新丢失
原因:id是分布式主键,但order_info表的分片键是user_id,ShardingSphere-JDBC 在UPDATE语句中无法从WHERE id = ?提取出user_id,因此降级为广播路由(发到所有库),而只有目标库有该id的数据,其他库更新 0 行——看似成功,实则数据未更新。
解决:强制在UPDATE语句中带上分片键:
// 错误:只传 id orderMapper.updateById(order); // 正确:传 id + user_id,让 ShardingSphere 能提取分片键 LambdaUpdateWrapper<OrderEntity> wrapper = new LambdaUpdateWrapper<>(); wrapper.eq(OrderEntity::getId, order.getId()) .eq(OrderEntity::getUserId, order.getUserId()); // 关键!带上分片键 orderMapper.update(order, wrapper);5.5 现象:@Select("SELECT * FROM order_info")注解查询,日志显示 SQL 未被改写,直连db_0
原因:MyBatis 的@Select注解 SQL 是在编译期解析的,ShardingSphere-JDBC 的 SQL 解析器(SQLStatementParserEngine)默认不处理注解 SQL,只处理 XML 中的 SQL。
解决:统一使用 XML 映射文件,或在@Select中显式指定表名为逻辑表名(非物理表名):
@Select("SELECT * FROM order_info") // ✅ 逻辑表名,ShardingSphere 能识别 // 而不是 @Select("SELECT * FROM db_0.order_info") // ❌ 物理表名,绕过分片6. 二次开发技巧:从改配置到换算法,三个可立即上手的改造点
拿到这个项目,你肯定不只想跑通,更想改成自己业务的样子。我总结了三个最高频的改造需求,每个都给出具体改法、验证步骤和避坑提示,照着做,10 分钟内就能生效。
6.1 改造点一:把user_id分片键换成order_no,且order_no是字符串类型
业务方说:“user_id有隐私合规风险,必须用订单号分片。”order_no是形如ORD20240520123456789的字符串,不能直接取模。你需要:
- 改实体类:在
OrderEntity中确保orderNo有getOrderNo()方法; - 写字符串哈希算法:新建
OrderNoShardingAlgorithm,继承StandardShardingAlgorithm<String>,doSharding中用value.hashCode() % 2; - 改配置:
application.yml中sharding-column: order_no,sharding-algorithm-name: order_no_hash; - 验证:启动后调用
POST /api/order创建订单,看日志是否输出Sharding order_no=ORD2024... to db index=1。
注意:字符串
hashCode()可能为负,务必用Math.abs(value.hashCode()) % shardingCount,否则路由错乱。
6.2 改造点二:增加一个新库db_2,把分片数从 2 扩到 3,不停机平滑迁移
这是最考验功底的改造。不能直接改sharding-count: 3,否则历史数据查不到。正确流程是:
| 步骤 | 操作 | 验证方式 |
|---|---|---|
| 1 | 新建物理库db_2,执行CREATE TABLE order_info LIKE db_0.order_info | mysql -e "SHOW DATABASES LIKE 'db_2'" |
| 2 | 修改application.yml,datasource.names加db_2,sharding-algorithms.db_mod.props.sharding-count: 3 | 启动不报错,sql-show: true日志显示路由到db_2 |
| 3 | 写迁移脚本:将db_0和db_1中user_id % 3 == 2的数据INSERT INTO db_2.order_info SELECT ... | 对比SELECT COUNT(*) FROM db_2.order_info与迁移脚本计算值 |
| 4 | 迁移完成后,重启应用,新订单全部写入三库 | 查db_2是否有新增订单 |
血泪经验:迁移脚本必须在业务低峰期执行,且加
FOR UPDATE锁住源表,避免迁移中产生新数据。
6.3 改造点三:对接公司统一的配置中心(Nacos),把分片规则动态化
现在所有分片配置都在application.yml,改一次要发版。你想把它抽到 Nacos:
- 加依赖:
spring-cloud-starter-alibaba-nacos-config; - 建 Nacos 配置:Data ID
sharding-demo-dev.yaml,GroupDEFAULT_GROUP,内容为spring.shardingsphere.rules[0].tables.order_info.database-strategy.standard.sharding-column=user_id; - 改启动类:加
@EnableConfigurationProperties(ShardingProperties.class),ShardingProperties类用@ConfigurationProperties("spring.shardingsphere")绑定; - 监听变更:用
@RefreshScope注解ShardingConfig类,或监听RefreshEvent事件,调用ShardingSphereDataSource.reload()。
提示:
ShardingSphereDataSource.reload()是 5.3.2 新增 API,可热重载分片规则,无需重启 JVM。
从那以后我每次给新项目接入分库分表,都强制走一遍这三步:先跑通这个springboot_shardingjdbc_mybatis原始工程,再改分片键,再扩库,最后接配置中心。它就像一把瑞士军刀,不花哨,但每一块刃都磨得够快——快到能削掉你对分库分表的最后一丝敬畏。希望帮到你。
本文还有配套的精品资源,点击获取