Sharding-JDBC 源码之 SQL 路由

Sharding-JDBC 系列

  1. 第一篇 Sharding-JDBC 源码之启动流程分析
  2. 第二篇 Sharding-JDBC 源码之 SQL 解析
  3. 第三篇 Sharding-JDBC 源码之 SQL 路由(本文)
  4. 第四篇 Sharding-JDBC 源码之 SQL 改写
  5. 第五篇 Sharding-JDBC 源码之 SQL 执行
  6. 第六篇 Sharding-JDBC 源码之结果集归并

接上文,在完成 SQL 解析之后,也就意味着我们拿到了逻辑 SQL 的抽象语法树及解析结果,
例如,以下SQL:

select goods_name from t_goods where goods_id=1 and type=0

解析之后的为抽象语法树见下图:
在这里插入图片描述

接下来,我们将继续学习SQL 路由过程。


路由类型

根据分片键划分路由

根据解析上下文匹配数据库和表的分片策略,生成路由路径。对于携带分片键的SQL,根据分片键的不同可以划分不同的路由:

  • 单片路由:分片键的操作符是 =
  • 多片路由:分片键的操作符是 IN
  • 范围路由:分片键的操作符是 BETWEEN
  • 广播路由: 不携带分片键的SQL。
根据分片键场景划分路由

根据分片键进行路由的场景,又细分以下三种类型:

  • 直接路由(强制路由):需使用HintAPI直接指定路由至库表,可适用分片键不在SQL中场景;
  • 标准路由(推荐):适用范围是不包含关联查询或仅包含绑定表之间关联查询的SQL,在分片运算符是 BETWEENIN 时,单表查询或关联查询生成的真实SQL数量是一致的;
  • 笛卡尔积路由:无法根据绑定表的关系定位分片规则,非绑定表之间的关联查询需要拆解为笛卡尔积组合执行。
不携带分片键的广播路由

不携带分片键的 SQL,则采取广播路由的方式,根据SQL类型又可以划分为以下5种:

  • 全库表路由:处理对数据库中与其逻辑表相关的所有真实表的操作,主要包括不带分片键的 DQLDML,以及 DDL 等;
  • 全库路由:处理数据库相关命令,用于库设置的 SET 类型的数据库管理命令,以及 TCL 这样的事务控制语句;
  • 全实例路由:用于 DCL 操作,授权语句针对的是数据库的实例;例如:CREATE USER xxx
  • 单播路由:获取某一真实表信息的场景,它仅需要从任意库中的任意真实表中获取数据即可。例如:DESCRIBE t_goods;
  • 阻断路由:用于屏蔽SQL对数据库的操作,命令不会在真实数据库中执行例如:USE order_db

SQL 路由

介绍完分片键类型,接下来我们从源码上来看是如何路由。以下继续以 select 查询为例,在上篇文章中,我们拿到了 SQLStatement 的实例 SelectStatement 对象,
在这里插入图片描述
在拿到 SelectStatement 对象后,开始进行路由,非 HintSQL 使用 ParsingSQLRouter 进行路由,执行 ParsingSQLRouter#route 方法:

    public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) {
   
   
        GeneratedKey generatedKey = null;
        // 如果是插入语句,获取生成的主键
        if (sqlStatement instanceof InsertStatement) {
   
   
            generatedKey = getGenerateKey(shardingRule, (InsertStatement) sqlStatement, parameters);
        }
        SQLRouteResult result = new SQLRouteResult(sqlStatement, generatedKey);
        // 通过优化引擎获取分库分表条件,存放在 ShardingConditions 对象中
        ShardingConditions shardingConditions = OptimizeEngineFactory.newInstance(shardingRule, sqlStatement, parameters, generatedKey).optimize();
        
        // ......省略,先分析优化引擎
    }

在上面代码片段中,优化引擎会去获取分库(表)的条件映射,看下 QueryOptimizeEngine#optimize 方法:

    public ShardingConditions optimize() {
   
   
        List<ShardingCondition> result = new ArrayList<>(orCondition.getAndConditions().size());
        for (AndCondition each : orCondition.getAndConditions()) {
   
   
            // 调用重载方法 optimize 封装 ShardingCondition 对象
            // 1. each.getConditionsMap() 按照列进行分组
            result.add(optimize(each.getConditionsMap()));
        }
        return new ShardingConditions(result);
    }
    
    // 重载方法 optimize 封装 ShardingCondition 对象
    private ShardingCondition optimize(final Map<Column, List<Condition>> conditionsMap) {
   
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值