分片配置的目的显而易见:就是将数据库分片规则和策略告诉sharding-jdbc
sharding-jdbc需要知道如下信息:
(1)哪些表需要分片
(2)需要分成哪些库?哪些表?名字分别是什么
(3)通过哪个字段(或哪些字段)进行分库分表
(4)具体的分库或分表算法什么怎样的
(5)分片规则和策略相关的一组表怎么处理
刚开始看官方的小例子,分片配置的代码有些懵逼,梳理了一下,需要如下类进行实现
DataSourceRule
TableRule
BindingTableRule
ShardingRule
这些对象的创建次序轴是这样的:
先看DataSourceRule
这个类可以理解为:存放所有被拆分的数据库对象和默认数据源的名称
这个类一共有两个属性:
(1)defaultDataSourceName:默认数据源的名字,那些不需要分片的数据表放到这个数据源中
(2)dataSourceMap:全部的数据源对象(DataSource),这是一个map结构,key:数据库的名字,value:数据源对象(DataSource)
public DataSourceRule(final Map<String, DataSource> dataSourceMap, final String defaultDataSourceName) { Preconditions.checkState(!dataSourceMap.isEmpty(), "Must have one data source at least."); this.dataSourceMap = dataSourceMap; if (1 == dataSourceMap.size()) { this.defaultDataSourceName = dataSourceMap.entrySet().iterator().next().getKey(); return; } if (Strings.isNullOrEmpty(defaultDataSourceName)) { this.defaultDataSourceName = null; return; } Preconditions.checkState(dataSourceMap.containsKey(defaultDataSourceName), "Data source rule must include default data source."); this.defaultDataSourceName = defaultDataSourceName; }
上面是构造函数,比较简单,做下面几件事情:
(1)数据源map不能为空,否则抛异常
(2)如果map的大小为1,默认数据源的名字就是这个唯一的数据源,可以理解为不分库只分表,或不分库分表
(3)如果存在默认数据源,则要判断这个数据源是否存在于map中
这个类的其它方法比较简单,通过注释就能明白什么意思
TableRule
这个对象用来存放逻辑表、所有的分片最小单位(DataNode)、分库策略、分表策略、是否动态表,下面分表解释含义:
(1)逻辑表:这个简单不解释
(2)分片最小单位:比如db_0.order_1,这个最小单位是通过计算来生成的,后面会讲到
(3)分库策略:定义分库算法的类
(4)分表策略:定义分表算法的类
(5)是否为动态表:表示实际表的名字和个数无法确认,是动态变化的,无法在程序中静态配置。比如:真实表的名称随着时间的推移会产生变化。
/** * 全属性构造器. * * <p>用于Spring非命名空间的配置.</p> * * <p>未来将改为private权限, 不在对外公开, 不建议使用非Spring命名空间的配置.</p> * * @deprecated 未来将改为private权限, 不在对外公开, 不建议使用非Spring命名空间的配置. */ @Deprecated public TableRule(final String logicTable, final boolean dynamic, final List<String> actualTables, final DataSourceRule dataSourceRule, final Collection<String> dataSourceNames, final DatabaseShardingStrategy databaseShardingStrategy, final TableShardingStrategy tableShardingStrategy) { Preconditions.checkNotNull(logicTable); this.logicTable = logicTable; this.dynamic = dynamic; this.databaseShardingStrategy = databaseShardingStrategy; this.tableShardingStrategy = tableShardingStrategy; if (dynamic) { Preconditions.checkNotNull(dataSourceRule); this.actualTables = generateDataNodes(dataSourceRule); } else if (null == actualTables || actualTables.isEmpty()) { Preconditions.checkNotNull(dataSourceRule); this.actualTables = generateDataNodes(Collections.singletonList(logicTable), dataSourceRule, dataSourceNames); } else { this.actualTables = generateDataNodes(actualTables, dataSourceRule, dataSourceNames); } }
这个是构造函数的代码:
(1)前几行比较简单,就是根据入参设置属性值
(2)紧接着是生成DataNode的代码
(3)如果是动态表,生成的DataNode只有数据源,表的名字没有
(4)如果真实表为空,则把逻辑表名作为真实表名(只分库不分表或不分库分表)
(5)其它情况,就会根据所有的数据源和真实表,通过笛卡尔积计算生成最小分片单元(DataNode)
/** * 根据数据源名称过滤获取真实数据单元. * * @param targetDataSources 数据源名称集合 * @param targetTables 真实表名称集合 * @return 真实数据单元 */ public Collection<DataNode> getActualDataNodes(final Collection<String> targetDataSources, final Collection<String> targetTables) { return dynamic ? getDynamicDataNodes(targetDataSources, targetTables) : getStaticDataNodes(targetDataSources, targetTables); }
上面这个方法是根据数据源列表和真实表列表获取最小分片单元。
这个方法会在分库和分表策略计算完毕后,得到路由到的数据库列表和数据表列表,但是不知道数据表和数据库的对应关系(这边表属于哪个数据库),通过这个方法来获取最小分片单元
这个方法会分两种情况
(1)如果是动态分表,则会拿这些需要路由的表和所有的分库做笛卡尔积计算(也就是说动态表这种场景,分多少个库一定是确定的,并且表要在每个库都动态新增)
(2)不是动态分表,会计算出这些数据库和数据表的真实对应关系
这个地方不太好理解,举个例子:
比如分了两个库,db0和db1,这个两个库中分别有下面这些表:
db0:order0,order1,order2
db1:order3,order4,order5
经过分库分表计算后,得到的结果是:需要查询两个库:db0和db1,两张表:order1和order5,我怎么知道order1是属于db0的,二order5是属于db1的呢?就是通过这个方法来计算
/** * 根据数据源名称过滤获取真实表名称. * * @param targetDataSources 数据源名称 * @return 真实表名称 */ public Collection<String> getActualTableNames(final Collection<String> targetDataSources) { Collection<String> result = new LinkedHashSet<>(actualTables.size()); for (DataNode each : actualTables) { if (targetDataSources.contains(each.getDataSourceName())) { result.add(each.getTableName()); } } return result; }
这个方法比较好理解,根据数据源名字获取这些数据源下面的所有真实表的名字
当进行了分库计算,再进行分表计算时,我只需要获取这些数据源下面的真实表,缩小了范围
int findActualTableIndex(final String dataSourceName, final String actualTableName) { int result = 0; for (DataNode each : actualTables) { if (each.getDataSourceName().equals(dataSourceName) && each.getTableName().equals(actualTableName)) { return result; } result++; } return -1; }
这个方法是根据数据源名字和表名字获取这个分片单元在actualTables中的索引,这个用于确定绑定表,讲绑定表时会详细讲解
BindingTableRule
如果两张表在任何场景下,分片规则完全一样,我们可以对这两张表进行绑定,这两张表互为绑定表,例如订单表和子订单表。关联表查询时,可以显著的提高查询效率,避免笛卡尔积查询。
这个对象只有一个属性:tableRules,这个列表中的表互为绑定表
/** * 根据其他Binding表真实表名称获取相应的真实Binding表名称. * * @param dataSource 数据源名称 * @param logicTable 逻辑表名称 * @param otherActualTable 其他真实Binding表名称 * @return 真实Binding表名称 */ public String getBindingActualTable(final String dataSource, final String logicTable, final String otherActualTable) { int index = -1; for (TableRule each : tableRules) { if (each.isDynamic()) { throw new UnsupportedOperationException("Dynamic table cannot support Binding table."); } index = each.findActualTableIndex(dataSource, otherActualTable); if (-1 != index) { break; } } Preconditions.checkState(-1 != index, String.format("Actual table [%s].[%s] is not in table config", dataSource, otherActualTable)); for (TableRule each : tableRules) { if (each.getLogicTable().equals(logicTable)) { return each.getActualTables().get(index).getTableName(); } } throw new IllegalStateException(String.format("Cannot find binding actual table, data source: %s, logic table: %s, other actual table: %s", dataSource, logicTable, otherActualTable)); }
一个sql语句中,如果几个表关联查询,并且这几个表互为绑定表,其中一个表进行了分片计算,其它表就不需要再次进行分片计算(绑定表的分片规则一样),就需要根据主表计算出其它表的真实名字,上面的方法就实现这个功能
(1)获取绑定表主表(已经进行了分片计算的表)位于actualTables中的索引
(2)根据索引和逻辑表名字获取绑定表子表名
绑定表的一个坑(版本1.3.1):
order和sub_order是绑定表,都以order_id进行分表。
写法一(正确的写法):SELECT * FROM order,sub_order WHERE order.order_id = sub_order.order_id and order.order_id = ?
写法二(错误的写法):SELECT * FROM sub_order,order WHERE order.order_id = sub_order.order_id and order.order_id = ?
写法二会导致不进行分表计算,很容易造成陷阱,可能是因为选主的算法,FROM后面的第一个表认为是主表,所用的绑定表的分库分别规则都以主表为准。所以写法二认为主表是sub_order,但是where条件中却是order.order_id,所以就不进行分表计算。
ShardingRule
这个对象会汇总DataSourceRule、TableRule、BindingTableRule、分表策略、分库策略
这个对象的构造方法中会传入DataSourceRule,TableRule对象中的构造方法中也有这个参数,
(1)在ShardingRule中,数据源对象会被存放起来,供后面使用。
(2)在TableRule中数据源对象是用来计算最小分片单元的。
这个对象中会设置分库和分表策略,TableRule中同样也有,优先级TableRule更高
相关推荐
6. **示例代码分析**:项目中的源码可以展示如何在Spring Boot应用中创建数据源、定义分片策略、注册ShardingSphere的数据源 bean,以及如何在业务代码中使用Sharding-JDBC进行数据库操作。 7. **测试与调试**:...
5. **实例源码分析**:源码中可能包含了Sharding-JDBC的启动配置、数据源配置、分片策略定义、SQL路由逻辑、以及MyBatis的相关配置。通过阅读源码,可以理解Sharding-JDBC是如何在实际应用中处理分库分表的SQL执行...
2. **加载配置**:Sharding-JDBC读取配置文件中的分片策略,这可能包括哈希分片、范围分片、复合分片等,以及数据库路由规则。 3. **创建逻辑表元数据**:根据配置,Sharding-JDBC构建逻辑表的元数据,用于后续的...
Sharding-JDBC作为一款Java客户端直连数据库的ORM框架,其工作原理是在JDBC层面上进行拦截,通过配置规则对SQL进行改写,实现数据的分片。它支持常见的数据库如MySQL、Oracle、PostgreSQL等,并且兼容JPA、MyBatis...
《sharding-jdbc架构介绍与源码分析》这篇文章主要探讨的是一个在Java编程领域中广泛使用的数据库分片框架——Sharding-JDBC。它在中国的大型高并发网络公司中扮演着关键角色,帮助这些企业解决数据存储和处理的挑战...
分片JDBC是JDBC的扩展,提供了诸如分片,读/写拆分和BASE事务之类的分布式功能。 特征 1.分片 分布式数据库中支持的聚合功能,分组依据,排序依据和限制SQL。 支持联接(内部/外部)查询。 分片运算符= ,支持...
《深入理解Sharding-JDBC:源码解析与实践探索》 在当今的互联网时代,数据库的性能和扩展性成为系统架构中的关键因素。Sharding-JDBC作为一款...因此,深入研究Sharding-JDBC源码,是每个Java开发者的必备技能之一。
三、Sharding-JDBC源码分析 1. SQL解析:Sharding-JDBC使用Apache Calcite进行SQL解析,将原始SQL转化为抽象语法树(AST),然后根据配置的分片规则对AST进行修改,生成针对各个Shard的SQL。 2. 分片策略:...
本文将深入探讨如何结合Druid和ShardingSphere实现更高效的数据分片策略,并通过源码分析加深理解。 首先,Druid作为数据库连接池,提供了优秀的性能监控、SQL拦截、日志打印等功能。其核心组件包括数据源、连接池...
还进行了扩展和优化,引入了多个开源组件,如分布式任务调度框架xxl-job、服务注册与发现组件zk+dubbo,以及数据库分片和分布式事务解决方案sharding-jdbc和seata,同时结合nacos作为配置中心。下面将详细讲解这些...
Sharding-JDBC作为一个轻量级Java库,可以直接嵌入到现有应用中,无需额外部署和依赖,通过JDBC接口实现对数据库的透明化分片操作。Sharding-Proxy则提供了服务端代理模式,支持MySQL和PostgreSQL协议,使得应用程序...
它主要分为两个部分:Sharding-JDBC 和 Sharding-Proxy,分别提供轻量级的 JDBC 层面的分片解决方案和代理层的分片服务。这两个组件都支持水平扩展,通过分片策略将数据分散到多个数据库中,从而提高系统的处理能力...
4. 分片键:每个需要分片的表都会有一个或多个分片键,这些键用于决定数据存储的位置。 三、ShardingSphere配置与实践 在"incubator-shardingsphere-example-dev"项目中,我们可以看到以下实践步骤: 1. 引入依赖...
1. **Sharding-JDBC**: 作为一个轻量级Java框架,它无需额外的中间件,可以直接嵌入到现有应用中,通过JDBC接口透明地实现数据分片。它可以与任何基于JDBC的应用兼容,如Spring、MyBatis等。 2. **Sharding-Proxy**...
这部分可能包含了ShardingSphere的数据分片策略分析,如基于范围、哈希值、时间戳等多种分片算法的示意图,以及如何根据业务需求选择合适的分片策略。 **五、02 读写分离** 这部分可能详细阐述了ShardingSphere的...
6. **Sharding模块**:分片策略实现,包括对各种分片策略的代码实现,如Range分片、Hash分片等。 通过对Mycat-Server-1.6源码的学习,开发者可以了解其内部工作机制,优化SQL执行效率,定制分片策略,甚至为Mycat...
总的来说,Apache ShardingSphere 4.1.1的源码分析可以帮助开发者深入理解分布式数据库中间件的设计理念和实现机制,对于提升数据库系统架构设计和优化能力具有重要价值。通过阅读源码,可以学习到数据库分片、读写...
1. 配置:在Hibernate的配置文件中,需要指定数据库连接信息,以及可能的分表相关的配置参数,如分片规则、分区字段等。这些配置可以根据具体的需求进行定制。 2. 实体类设计:实体类需要包含用于分表的属性,并...
4. **Sharding JDBC**:作为数据库分片工具,Sharding JDBC提供了一种无侵入式的解决方案,使得应用程序无需感知数据库分片的存在。它支持水平和垂直分片,能有效提高数据库的并发处理能力,并且简化了分布式数据库...