ShardingSphere-JDBC分片改写引擎

本文深入探讨了ShardingSphere-JDBC的改写引擎,它使用装饰器模式,包括ShardingSQLRewriteContextDecorator、ShadowSQLRewriteContextDecorator和EncryptSQLRewriteContextDecorator,对SQL进行改写以适应分片环境。改写引擎处理多种SQL语句,如INSERT、SELECT等,通过构造SQLTokenGenerator进行改写。改写流程包括构造SQLToken、执行改写等步骤,确保SQL能在分片数据库中正确执行。
摘要由CSDN通过智能技术生成

前言

上文ShardingSphere-JDBC分片路由引擎中介绍了分片流程中的路由引擎,最终获取了路由结果;本文要介绍的改写引擎需要使用路由结果来对SQL进行改写,改写成可以被正确的分库分表能够执行的SQL;这里面涉及对各种SQL改写的情况众多,接下来本文会进行一一分析。

改写装饰器

重写引擎同样使用了装饰器模式,提供了接口类SQLRewriteContextDecorator,实现类包括:

  • ShardingSQLRewriteContextDecorator:分片SQL改写装饰器;
  • ShadowSQLRewriteContextDecorator:影子库SQL改写装饰器;
  • EncryptSQLRewriteContextDecorator:数据加密SQL改写装饰器;

默认加载ShardingSQLRewriteContextDecoratorEncryptSQLRewriteContextDecorator,使用java.util.ServiceLoader来加载重写装饰器,需要在META-INF/services/中指定具体的实现类:

org.apache.shardingsphere.sharding.rewrite.context.ShardingSQLRewriteContextDecorator
org.apache.shardingsphere.encrypt.rewrite.context.EncryptSQLRewriteContextDecorator

装饰器可以叠加,所以提供了优先级功能OrderAware,同时每个装饰器都有对应的规则,大致如下所示:

装饰器-SQLRewriteContextDecorator 规则-BaseRule 优先级-Order
ShardingSQLRewriteContextDecorator ShardingRule 0
EncryptSQLRewriteContextDecorator EncryptRule 20
ShadowSQLRewriteContextDecorator ShadowRule 30

只有在配置了相关BaseRule,对应的SQLRewriteContextDecorator才能生效,最常见的是ShardingSQLRewriteContextDecorator,下面重点介绍此装饰器;

改写引擎

不同的SQL语句,需要处理的改写都不一样,改写引擎的整体结构划分如下图所示(来自官网):
在这里插入图片描述

执行改写引擎之前需要做一些准备工作,整个改写流程大致分为以下几步:

  • 根据不同的改写装饰器构造不同的SQLTokenGenerator列表;
  • 根据SQLTokenGenerator生成对应的SQLToken
  • 改写引擎根据SQLToken执行改写操作;

构造SQLTokenGenerator

不同的装饰器需要构造不同的SQLTokenGenerator列表,以最常见的ShardingSQLRewriteContextDecorator为例,会准备如下13种SQLTokenGenerator

    private Collection<SQLTokenGenerator> buildSQLTokenGenerators() {
   
        Collection<SQLTokenGenerator> result = new LinkedList<>();
        addSQLTokenGenerator(result, new TableTokenGenerator());
        addSQLTokenGenerator(result, new DistinctProjectionPrefixTokenGenerator());
        addSQLTokenGenerator(result, new ProjectionsTokenGenerator());
        addSQLTokenGenerator(result, new OrderByTokenGenerator());
        addSQLTokenGenerator(result, new AggregationDistinctTokenGenerator());
        addSQLTokenGenerator(result, new IndexTokenGenerator());
        addSQLTokenGenerator(result, new OffsetTokenGenerator());
        addSQLTokenGenerator(result, new RowCountTokenGenerator());
        addSQLTokenGenerator(result, new GeneratedKeyInsertColumnTokenGenerator());
        addSQLTokenGenerator(result, new GeneratedKeyForUseDefaultInsertColumnsTokenGenerator());
        addSQLTokenGenerator(result, new GeneratedKeyAssignmentTokenGenerator());
        addSQLTokenGenerator(result, new ShardingInsertValuesTokenGenerator());
        addSQLTokenGenerator(result, new GeneratedKeyInsertValuesTokenGenerator());
        return result;
    }

以上实现类的公共接口类为SQLTokenGenerator,提供了是否生效的公共方法:

public interface SQLTokenGenerator {
   
    boolean isGenerateSQLToken(SQLStatementContext sqlStatementContext);
}

各种不同的SQLTokenGenerator并不是每次都能生效的,需要根据不同SQL语句进行判断,SQL语句在解析引擎中已经被解析为SQLStatementContext,这样可以通过SQLStatementContext参数进行判断;

TableTokenGenerator

TableToken生成器,主要用于对表名的改写;

    public boolean isGenerateSQLToken(final SQLStatementContext sqlStatementContext) {
   
        return true;
    }

可以发现这里对是否生成SQLToken没有任何条件,直接返回true;但是在生成TableToken的时候是会检查是否存在表信息以及是否配置相关表TableRule

DistinctProjectionPrefixTokenGenerator

DistinctProjectionPrefixToken生成器,主要对聚合函数和去重的处理:

    public boolean isGenerateSQLToken(final SQLStatementContext sqlStatementContext) {
   
        return sqlStatementContext instanceof SelectStatementContext && !((SelectStatementContext) sqlStatementContext).getProjectionsContext().getAggregationDistinctProjections().isEmpty();
    }

首先必须是select语句,同时包含:聚合函数和Distinct去重,比如下面的SQL:

select sum(distinct user_id) from t_order where order_id = 101

改写之后的SQL如下所示:

Actual SQL: ds0 ::: select DISTINCT user_id AS AGGREGATION_DISTINCT_DERIVED_0 from t_order1 where order_id = 101
Actual SQL: ds1 ::: select DISTINCT user_id AS AGGREGATION_DISTINCT_DERIVED_0 from t_order1 where order_id = 101
ProjectionsTokenGenerator

ProjectionsToken生成器,聚合函数需要做派生处理,比如AVG函数

    public boolean isGenerateSQLToken(final SQLStatementContext sqlStatementContext) {
   
        return sqlStatementContext instanceof SelectStatementContext && !getDerivedProjectionTexts((SelectStatementContext) sqlStatementContext).isEmpty();
    }
    
    private Collection<String> getDerivedProjectionTexts(final SelectStatementContext selectStatementContext) {
   
        Collection<String> result = new LinkedList<>();
        for (Projection each : selectStatementContext.getProjectionsContext().getProjections()) {
   
            if (each instanceof AggregationProjection && !((AggregationProjection) each).getDerivedAggregationProjections().isEmpty()) {
   
                result.addAll(((AggregationProjection) each).getDerivedAggregationProjections().stream().map(this::getDerivedProjectionText).collect(Collectors.toList())
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ShardingSphere-JDBC 是一款开源的分布式数据库中间件,支持多种关系型数据库的分库分表和读写分离等功能。其提供了丰富的分片算法,默认情况下已经支持了常见的分片算法,如按照主键、按照范围等。如果默认的分片算法无法满足需求,可以通过自定义分片算法来实现更为灵活的分片策略。 在 ShardingSphere-JDBC 中,自定义分片算法需要实现 `ShardingAlgorithm` 接口。该接口包括两个方法: 1. `doSharding(Collection<String> availableTargetNames, ShardingValue shardingValue)`:根据分片值和可用的分片数据源名称进行分片计算,返回分片后需要访问的分片数据源名称集合。 2. `getType()`:获取分片算法类型。 自定义分片算法需要在 `ShardingSphereDataSource` 中进行配置,示例如下: ```java ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration(); shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration()); shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item"); shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig( new StandardShardingStrategyConfiguration("user_id", new MyDatabaseShardingAlgorithm())); shardingRuleConfig.setDefaultTableShardingStrategyConfig( new StandardShardingStrategyConfiguration("order_id", new MyTableShardingAlgorithm())); DataSource dataSource = ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(), Collections.singleton(shardingRuleConfig), new Properties()); ``` 其中 `MyDatabaseShardingAlgorithm` 和 `MyTableShardingAlgorithm` 分别为自定义的分库分表算法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值