首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

6.sjdbc源码之路由

继续以模块中的为基础,剖析分库分表核心功能路由

ShardingPreparedStatementTest.java中查询调用,即调用ShardingPreparedStatement中的方法,核心源码如下:

通过上面的源码可知,SQL查询几个核心:路由,执行和结果合并,这篇文章主要分析路由的实现;

路由选择

接下来分析下面这段代码是如何取得路由信息的:

说明:SQLRouter接口有两个实现类:DatabaseHintSQLRouterParsingSQLRouter,两者之间如何选择,源码如下:

DatabaseHintSQLRouter

所以,选择DatabaseHintSQLRouter的用法如下:

所以,Hint语法还是比较简单的。由于我们的测试用例没有使用Hint语法强制路由数据库&表,所以调用ParsingSQLRouter中的route()方法;

ParsingSQLRouter

ParsingSQLRouter路由核心源码如下:

简单路由or复杂路由

由上面这段代码可知,满足如下任意一个条件就走简单路由,否则为复杂路由,假设sharding规则如下:

是否只有一张表

说明:这个"一张表"并不是指SQL中只有一张表,而是有分库分表规则的表数量,例如AbstractShardingJDBCDatabaseAndTableTest中这段构造ShardingRule的源码,总计有三张表有配置规则:t_order,t_order_item,t_config。所以如果有这样的SQL:,只有t_order涉及sharding规则,t_status并不涉及,所以任然认为"只有一张表";

是否都是绑定表

说明:isAllBindingTables(tableNames)判断tableNames是否都属于绑定表,根据刚才那段构造ShardingRule的源码可知:,和互为绑定表,那么:这个SQL只有和两个表且互为绑定表,那么shardingRule.isAllBindingTables(tableNames)为true;

是否属于默认数据源

说明:如果SQL中涉及的表全部属于默认数据源中,那么无论多少张表,都认为isAllInDefaultDataSource()为true,即走简单路由。

表是否属于默认数据源的判断依据:不在中,如果是spring配置方式,则不在中。例如如下配置,和都有表规则,如果SQL中有这两张表的任何一张表,都认为不属于默认数据源:

简单路由

执行SQL:时,由于SQL中只有一个表(1 == tableNames.size()),所以路由引擎是SimpleRoutingEngine;核心源码如下:

数据源路由详细解读

由于数据源的sharding策略为:

where条件为,即where条件中有,根据取模路由策略,当为奇数时,数据源为;当为偶数时,数据源为;

表路由详细解读

表的sharding策略为:

where条件中有,根据取模路由策略,当为奇数时,表为;当为偶数时,表为;

结论:最终需要执行SQL的数据节点(DataNode,由数据源名称和数据表组成)的总个数为:路由到的数据源个数*路由到的实际表个数

示例

下面给出几个路由示例,以便更好的理解分库分表路由规则:

示例1where o.order_id=1001 AND o.user_id=10,user_id=10所以路由得到数据源为dataSource_jdbc_0; order_id=1001,路由得到实际表为t_order_1;那么最终只需在数据节点上执行即可

示例2where o.order_id=1000,user_id没有值所以路由得到所有数据源dataSource_jdbc_0和dataSource_jdbc_1; order_id=1000,路由得到实际表为t_order_0;那么最终需在和两个数据节点执行;

示例3where o.user_id=11,user_id=11所以路由得到数据源为dataSource_jdbc_1; order_id没有值所以路由得到实际表为t_order_0和t_order_1;那么最终需要在和两个数据节点执行即可;

复杂路由

首先构造这种复杂路由场景t_order和t_order_item分库分表且绑定表关系,加入一个新的分库分表t_config,执行的SQL为:

构造的这个SQL会走复杂路由的逻辑(不是DDL,有三张表,t_config和t_order/t_order_item不是绑定表关系,t_order/t_order_item有分库分表规则所以不属于默认数据源);

复杂路由引擎的核心逻辑就是拆分成多个简单路由,然后求笛卡尔积,复杂路由核心源码如下:

由上面源码分析可知,会分别对t_config和t_order构造简单路由(t_order_item和t_order是绑定关系,二者取其一即可);

t_config需要分库不需要分表(因为不涉及分表),所以t_config这个逻辑表的简单路由结果为:dataSource_jdbc_0.t_config和dataSource_jdbc_1.t_config,有2个数据节点;

t_order_item分库分表,且有请求参数user_id=10和order_id=1001,所以t_order_item的简单路由结果为:dataSource_jdbc_0.t_order_item_1,只有1个数据节点(user_id=10路由数据源dataSource_jdbc_0,order_id=1001路由表t_order_item_1)。

CartesianRoutingEngine

如上分析,求得简单路由结果集后,求笛卡尔积就是复杂路由的最终路由结果,笛卡尔积路由引擎CartesianRoutingEngine的核心源码如下:

时输出的结果如下,可以看到重写后的1条实际SQL:(t_order_item与t_order是绑定表,保持一致):

如果把SQL条件做如下调整:

这样的话:

t_config需要分库不需要分表(因为不涉及分表),所以t_config这个逻辑表的简单路由结果为:dataSource_jdbc_0.t_config和dataSource_jdbc_1.t_config,有2个数据节点;

t_order_item分库分表,但是只有请求参数order_id=1001,所以t_order_item的简单路由结果为:dataSource_jdbc_0.t_order_item_1和dataSource_jdbc_1.t_order_item_1,也有2个数据节点。

那么最终的路由结果如下,两个数据源dataSource_jdbc_0 和dataSource_jdbc_1 都会路由到:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180829G09J2R00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券