ShardingSphere的路由流程

举报
周杰伦本人 发表于 2022/10/30 18:52:05 2022/10/30
【摘要】 ShardingSphere的路由流程 路由的入口 路由流程分析 总结 ShardingSphere的路由流程本篇文章源码基于4.0.1版本ShardingSphere的分片引擎从解析引擎到路由引擎到改写引擎到执行引擎再到归并引擎,一步一步对分片操作进行处理,我们这篇文章先从解析引擎开始,深入分析一下Sql的解析引擎处理流程。 路由的入口ShardingStatement是支持分片的Sta...

ShardingSphere的路由流程

本篇文章源码基于4.0.1版本

ShardingSphere的分片引擎从解析引擎到路由引擎到改写引擎到执行引擎再到归并引擎,一步一步对分片操作进行处理,我们这篇文章先从解析引擎开始,深入分析一下Sql的解析引擎处理流程。

路由的入口

ShardingStatement是支持分片的Statement,以它的executeQuery()执行查询操作的方法为入口,看看分片路由做了什么。这里调用自身的shard()方法进行分片,这个方法中创建SimpleQueryShardingEngine对象,

SimpleQueryShardingEngine继承了抽象类BaseShardingEngine,作用就是用于简单查询的分片引擎,创建完对象信息后调用shard()方法进行分片,核心操作是BaseShardingEngine的子类实现的route()方法,这里是模板方法的体现:先进行准备参数,然后执行路由,然后进行Sql的转换和改写,其中准备参数的方法和执行路由的方法由子类实现,它的子类有SimpleQueryShardingEngine和PreparedQueryShardingEngine,这里用到的是SimpleQueryShardingEngine,SimpleQueryShardingEngine的路由方法中直接调用了语句路由引擎类StatementRoutingEngine

StatementRoutingEngine的route()方法:

public SQLRouteResult route(final String logicSQL) {
    SQLStatement sqlStatement = shardingRouter.parse(logicSQL, false);
    return masterSlaveRouter.route(shardingRouter.route(logicSQL, Collections.emptyList(), sqlStatement));
}

这里先通过ShardingRouter这个类进行了分片路由,然后通过ShardingMasterSlaveRouter进行主从路由,下面就分片路由这个方法看看它具体是怎么进行路由的

路由流程分析

ShardingRouter的route()方法:

public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) {
    Optional<ShardingStatementValidator> shardingStatementValidator = ShardingStatementValidatorFactory.newInstance(sqlStatement);
    if (shardingStatementValidator.isPresent()) {
        shardingStatementValidator.get().validate(shardingRule, sqlStatement, parameters);
    }
    SQLStatementContext sqlStatementContext = SQLStatementContextFactory.newInstance(metaData.getRelationMetas(), logicSQL, parameters, sqlStatement);
    Optional<GeneratedKey> generatedKey = sqlStatement instanceof InsertStatement
            ? GeneratedKey.getGenerateKey(shardingRule, metaData.getTables(), parameters, (InsertStatement) sqlStatement) : Optional.<GeneratedKey>absent();
    ShardingConditions shardingConditions = getShardingConditions(parameters, sqlStatementContext, generatedKey.orNull(), metaData.getRelationMetas());
    boolean needMergeShardingValues = isNeedMergeShardingValues(sqlStatementContext);
    if (sqlStatementContext.getSqlStatement() instanceof DMLStatement && needMergeShardingValues) {
        checkSubqueryShardingValues(sqlStatementContext, shardingConditions);
        mergeShardingConditions(shardingConditions);
    }
    RoutingEngine routingEngine = RoutingEngineFactory.newInstance(shardingRule, metaData, sqlStatementContext, shardingConditions);
    RoutingResult routingResult = routingEngine.route();
    if (needMergeShardingValues) {
        Preconditions.checkState(1 == routingResult.getRoutingUnits().size(), "Must have one sharding with subquery.");
    }
    SQLRouteResult result = new SQLRouteResult(sqlStatementContext, shardingConditions, generatedKey.orNull());
    result.setRoutingResult(routingResult);
    if (sqlStatementContext instanceof InsertSQLStatementContext) {
        setGeneratedValues(result);
    }
    return result;
}
  1. 利用ShardingStatementValidatorFactory分片语句验证器工厂类创建ShardingStatementValidator分片语句验证器对象,校验器校验的是InsertStatement和UpdateStatement这两类SQL语句,校验器功能就是校验SQL语句是否支持分片操作,当判断存在重复的键值列并且这个列是分片键的时候检验不通过
  2. 获取Sql语句的上下文,同样是使用了SQLStatementContextFactory工厂类创建SQLStatementContext实例,SQLStatementContext的主要功能就是一个承上启下的作用,用来进行数据的存储和传递
  3. 判断SQL语句是否为插入语句,如果是的话调用GeneratedKey类来生成主键,生成主键的逻辑我们前面的文章分析了,支持UUID、雪花算法等
  4. 获取分片条件,具体来说判断语句上下文对象,如果是插入语句的上下文,通过用于插入子句的分片条件引擎InsertClauseShardingConditionEngine创建分片条件,否则使用where 子句的分片条件引擎WhereClauseShardingConditionEngine创建分片条件
  5. 判断是否需要进行合并分片条件操作,如果是DML语句并且需要合并的话,调用mergeShardingConditions()方法进行分片条件合并
  6. 执行路由,这里是核心代码,同样使用了工厂模式,路由引擎工厂类RoutingEngineFactory创建路由引擎,执行完路由后路由结果对象RoutingResult对象,路由引擎有很多种,不同的路由策略对应不同的路由引擎。
  7. 构建SQLRouteResult对象,将RoutingResult对象设置到了SQLRouteResult对象中,填充自动生成的分片键,返回结果。

总结

这篇文章主要讲了ShardingSphere的路由流程,入口以ShardingStatement的执行查询操作的方法为入口,最终定位到路由流程是ShardingRouter的route()方法,这个方法中大致先进行校验是否可以分片操作,然后创建Sql语句的上下文,判断是否需要生成主键,获取分片条件,判断是否需要合并分片条件,最终选择不同的路由引擎执行路由操作,将路由结果对象包装成SQLRouteResult对象并返回。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。