分库分表核心原理揭秘 📅 发布时间:2026/7/5 6:15:44 👁️ 浏览次数: 分库分表本质就是在一次 SQL 执行前动态决定用哪个数据库连接DataSource用哪张真实表table_xx而MyBatis / MyBatis-Plus 本身并不具备分库分表能力真正做到“动态切换”的是拦截器 路由规则 ThreadLocal 上下文。在 SQL 真正发送到数据库之前通过拦截器计算路由规则动态替换 DataSource 和表名。ORM 框架https://gitee.com/laomaodu/orm-framework分库分库并不是运行时创建数据库连接而是系统启动时初始化多个 DataSource执行 SQL 时通过 AbstractRoutingDataSource 根据 ThreadLocal 中的路由 key 动态选择目标 DataSource从对应的连接池中获取连接。1️⃣ 多数据源准备前提spring:datasource:db0: ...db1: ...db2: ...系统启动时所有 DataSource 都初始化放入一个 Map 中MapString, DataSource dataSourceMap;public class DynamicDataSource extends AbstractRoutingDataSource { Override protected Object determineCurrentLookupKey() { return DataSourceContext.get(); } }每次 SQL 执行前Spring 会调用determineCurrentLookupKey()返回值决定使用哪个 DataSourceThreadLocal 保存“当前库”public class DataSourceContext { private static final ThreadLocalString HOLDER new ThreadLocal(); public static void set(String dbKey) { HOLDER.set(dbKey); } public static String get() { return HOLDER.get(); } }4️⃣ 在执行前设置库String dbKey db (userId % 2);DataSourceContext.set(dbKey);Bean public DataSource dataSource() { MapObject, Object targetDataSources new HashMap(); targetDataSources.put(db0, dataSource0()); targetDataSources.put(db1, dataSource1()); DynamicDataSource ds new DynamicDataSource(); ds.setDefaultTargetDataSource(dataSource0()); ds.setTargetDataSources(targetDataSources); return ds; }public class DynamicDataSource extends AbstractRoutingDataSource { Override protected Object determineCurrentLookupKey() { return DataSourceContext.get(); } } public class DataSourceContext { private static final ThreadLocalString HOLDER new ThreadLocal(); public static void set(String key) { HOLDER.set(key); } public static String get() { return HOLDER.get(); } public static void clear() { HOLDER.remove(); } }// 2. 分库规则 String dbKey db (userId % 2); DataSourceContext.set(dbKey);MyBatis ↓ DynamicDataSource.getConnection() ↓ determineCurrentLookupKey() ↓ DataSourceContext.get() → db1 ↓ targetDataSources.get(db1) ↓ db1DataSource.getConnection() ↓ 从 db1 的连接池拿 Connection分表分表是如何“动态切换表名”的select * from order where id ?MyBatis 最终会生成BoundSqlString sql boundSql.getSql();Intercepts({ Signature( type Executor.class, method query, args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} ) }) public class ShardingInterceptor implements Interceptor { }long userId getUserId(param); String table order_ (userId % 16);///方法2 SQLParser.parse(sql).replaceTable();完整一次执行流程串起来1. Mapper 方法调用 2. 分库分表拦截器触发 3. 从参数中取分片键userId / orderId 4. 计算 - dbKey userId % 2 - table order_ (userId % 16) 5. ThreadLocal 设置 dbKey 6. SQL 中 order → order_xx 7. Executor 使用正确 DataSource 8. JDBC 执行最终 SQL为什么必须用 ThreadLocal一个请求 一个线程同一线程内多次 SQL必须走同一个库ThreadLocal无侵入自动隔离这是分库分表的线程级上下文基础ShardingSphere它内置了事务传播和多数据源管理。手动实现容易错。ShardingSphere JDBC 本质上是一个增强版 DataSource在 SQL 执行前通过解析 SQL 和分片算法计算路由结果动态选择目标数据源并重写 SQL这与手写 AbstractRoutingDataSource 的原理完全一致只是做了工程级封装。MyBatis↓ShardingSphereDataSource ←等价于你的 DynamicDataSource↓真实 DataSourcedb0 / db1↓MySQL刚刚手写的ShardingSphere 对应DynamicDataSourceShardingSphereDataSourceThreadLocalSQL Hint / 内部上下文分库算法ShardingAlgorithmSQL replaceSQL Rewrite EnginedependencygroupIdorg.apache.shardingsphere/groupIdartifactIdshardingsphere-jdbc-core-spring-boot-starter/artifactIdversion5.5.0/version/dependency⚠️ 不要再引 dynamic-datasource数据库ds0.order_0ds0.order_1ds1.order_0ds1.order_1datasource→ 配置所有物理库分库actual-data-nodes→ 分库分表映射关系逻辑表对应哪些物理表database-strategy→ 分库规则table-strategy→ 分表规则sharding-algorithms→ 定义具体的分库/分表算法表达式sql-show→ 打印 SQL观察路由结果spring: shardingsphere: # -------------------------- # 数据源配置分库用 # -------------------------- datasource: # 定义所有的数据源名称用逗号分隔 names: ds0, ds1 # 数据源 ds0 的具体配置 ds0: type: com.zaxxer.hikari.HikariDataSource # 使用 HikariCP 连接池 jdbc-url: jdbc:mysql://localhost:3306/db0 # 连接的数据库地址 username: root # 数据库用户名 password: 123456 # 数据库密码 # 数据源 ds1 的具体配置 ds1: type: com.zaxxer.hikari.HikariDataSource jdbc-url: jdbc:mysql://localhost:3306/db1 username: root password: 123456 # -------------------------- # 分片规则分库分表策略 # -------------------------- rules: sharding: # 配置具体的分表对象 tables: order: # 表名逻辑名 # 实际物理表的数据源与表名 # ds$-{0..1} - ds0, ds1 # order_$-{0..1} - order_0, order_1 actual-data-nodes: ds$-{0..1}.order_$-{0..1} # 分库策略 database-strategy: standard: sharding-column: user_id # 根据哪个字段决定分库 sharding-algorithm-name: db-inline # 使用的分库算法 # 分表策略 table-strategy: standard: sharding-column: user_id sharding-algorithm-name: table-inline # 使用的分表算法 # -------------------------- # 分库和分表算法定义 # -------------------------- sharding-algorithms: # 分库算法 db-inline: type: INLINE # 内联表达式算法 props: algorithm-expression: ds${user_id % 2} # 例如 user_id3 - 3%21 - 使用 ds1 数据源 # 分表算法 table-inline: type: INLINE props: algorithm-expression: order_${user_id % 2} # 例如 user_id3 - 3%21 - 使用 order_1 表 # -------------------------- # ShardingSphere 全局配置 # -------------------------- props: sql-show: true # 打印最终执行的 SQL方便调试和验证分库分表是否生效dbKey db userId % 2; -》algorithm-expression: ds${user_id % 2}table order_ userId % 2;-》algorithm-expression: order_${user_id % 2}ShardingSphere内部 SQL 路由引擎自动选择 ds0 / ds1AST 级 SQL Rewrite支持 join / 子查询Select(select * from order where user_id #{userId})Order select(Param(userId) Long userId);ShardingSphere 实际执行 select * from order_1 where user_id ? -- DataSource ds1场景结论单表百万级不需要分表但不分库可选分库 分表必须分库 事务必须多表 join必须
AI印象派艺术工坊集成WebP支持:高效图像格式转换部署教程 AI印象派艺术工坊集成WebP支持:高效图像格式转换部署教程 1. 为什么需要WebP?一张图说清效率差距 你有没有遇到过这样的情况:刚用AI艺术工坊生成了4张惊艳的梵高油画风格图,想发到朋友圈却卡在上传环节——原图动辄5MBÿ… 2026/7/5 6:15:10
YOLOE RepRTA技术揭秘:文本嵌入为何零开销 YOLOE RepRTA技术揭秘:文本嵌入为何零开销 你有没有遇到过这样的困惑:明明只加了一行提示词,模型推理速度却明显变慢?显存占用突然飙升?训练时一切正常,部署后却卡在文本编码环节?在开放词汇目… 2026/7/4 19:13:10
jetson xavier nx助力高性能服务机器人设计 以下是对您提供的博文内容进行 深度润色与工程化重构后的版本 。全文已彻底去除AI生成痕迹,采用真实嵌入式系统工程师+机器人算法开发者双重视角撰写,语言更贴近一线技术博客风格:有经验、有细节、有踩坑教训、有可复用代码逻辑,同时严格遵循您提出的全部格式与表达要求(… 2026/7/4 14:39:09
Android Keymaster/KeyMint:硬件级密钥管理与认证原理与NPI实践 1. 项目概述:从NPI工程师的视角看Keymaster在Android设备的新产品导入(NPI)项目中,安全模块的集成与验证往往是决定产品能否顺利量产、甚至能否通过运营商或特定市场准入认证的关键一环。作为一名在一线摸爬滚打多年的NPI工程师&a… 2026/7/5 6:13:49
61-NIN(补充端侧部署和云端部署的概念) 基于架构图的 VGG Net 与 NiN Net 深度分析这张图清晰对比了VGG 网络和NiN 网络的核心架构、基础模块设计,直观展现了两种经典 CNN 的设计思路差异,核心围绕「卷积模块设计」「分类头架构」「核心创新点」三个维度展开,以下是完整分析&#x… 2026/7/5 6:11:49
2026最新7款AI编程助手平替实测 我做了一个不太公平的对比:让 5 款 AI 编程工具都去处理一段我同事写的「屎山代码」,看谁能在不崩的情况下给出建议。作为做ToB系统5年的老兵,我前前后后试用过不下10款AI编程工具,最近团队要做新的积分系统迭代,我特意… 2026/7/5 6:09:48
实战指南:深度解析Windows Defender永久禁用技术原理与实现 实战指南:深度解析Windows Defender永久禁用技术原理与实现 【免费下载链接】defender-control An open-source windows defender manager. Now you can disable windows defender permanently. 项目地址: https://gitcode.com/gh_mirrors/de/defender-control … 2026/7/5 6:09:48
2026年选钢格板品牌,这三个指标帮你避坑 钢格板作为工业平台、沟盖板、楼梯踏步的核心材料,其质量直接关系到工程安全与使用寿命。然而,2025年钢格板行业数据显示,市场流通产品中约12%存在材料虚标或焊接质量问题(中国钢结构协会2025年鉴)。你可能也遇到过这种… 2026/7/5 6:07:48
别被忽悠了!1000-10000元档位电钢琴横向评测,谁是全能战士? 选购电钢琴时,切忌被花哨的噱头忽悠。电钢琴的本质是乐器,核心在于“手感”与“音色”。以下为您梳理选购电钢琴必须关注的核心避坑指南,并基于1000-10000元价位,为您横向评测并推荐十款热门电钢琴(包含三款派德拉机型… 2026/7/5 6:05:48
6个月转型AI工程师:实战路径与核心技能 1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公… 2026/7/5 0:01:32
TPAFE0808与PIC18F87K22的多通道信号采集方案 1. 项目背景与核心需求在工业自动化、医疗设备和科研仪器等领域,多通道信号采集与系统监测是基础且关键的技术需求。传统方案往往面临通道数量不足、信号调理复杂、系统集成度低等问题。TPAFE0808作为一款8通道模拟前端芯片,与PIC18F87K22微控制器的组合… 2026/7/5 0:01:32
STC3115与PIC18LF26K80构建高精度电池管理系统 1. STC3115与PIC18LF26K80在电池管理系统中的核心价值在现代电子设备中,电池管理系统(BMS)的重要性不亚于设备的核心处理器。STC3115作为一款高精度电池电量监测IC,与PIC18LF26K80微控制器的组合,构成了一个既能精确监控又能智能管理的完整解… 2026/7/5 0:05:36
6个月转型AI工程师:实战路径与核心技能 1. 项目概述:6个月转型AI工程师的可行性路径在2023年大模型技术爆发的背景下,AI工程师岗位需求同比增长217%(LinkedIn数据)。不同于传统算法工程师需要3-5年培养周期,现代AI工程师更侧重工程化落地能力。我在硅谷科技公… 2026/7/5 0:01:32
TPAFE0808与PIC18F87K22的多通道信号采集方案 1. 项目背景与核心需求在工业自动化、医疗设备和科研仪器等领域,多通道信号采集与系统监测是基础且关键的技术需求。传统方案往往面临通道数量不足、信号调理复杂、系统集成度低等问题。TPAFE0808作为一款8通道模拟前端芯片,与PIC18F87K22微控制器的组合… 2026/7/5 0:01:32
STC3115与PIC18LF26K80构建高精度电池管理系统 1. STC3115与PIC18LF26K80在电池管理系统中的核心价值在现代电子设备中,电池管理系统(BMS)的重要性不亚于设备的核心处理器。STC3115作为一款高精度电池电量监测IC,与PIC18LF26K80微控制器的组合,构成了一个既能精确监控又能智能管理的完整解… 2026/7/5 0:05:36