《è“

核心内容摘要

探索未知,点亮视界:一场关于高清与学习的精彩碰撞
mdapptv:开启你的视界新纪元,沉浸式娱乐体验触手可及

探索未知,连接无限:520886.com美国网站,开启你的全球视野新篇章

分库分表本质就是在一次 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 %

;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(); } }//

分库规则 String dbKey db (userId %

; DataSourceContext.set(dbKey);MyBatis ↓ DynamicDataSource.getConnection() ↓ determineCurrentLookupKey() ↓ DataSourceContext.get() → db1 ↓ targetDataSources.get(db

↓ 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 %

;///方法2 SQLParser.parse(sql).replaceTable();完整一次执行流程串起来

Mapper 方法调用

分库分表拦截器触发

从参数中取分片键userId / orderId

计算 - dbKey userId % 2 - table order_ (userId %

16)

ThreadLocal 设置 dbKey

SQL 中 order → order_xx

Executor 使用正确 DataSource

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/artifactIdversion

5.

0/version/dependency⚠️ 不要再引 dynamic-datasource数据库ds

order_0ds

order_1ds

order_0ds

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$-{

.1} - ds0, ds1 # order_$-{

.1} - order_0, order_1 actual-data-nodes: ds$-{

.1}.order_$-{

.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必须

www.bet888.cn-www.bet888.cn最新ios版v.18.79.06-码云下载应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123