前言
上文ShardingSphere-JDBC分片解析引擎中介绍了分片流程中的解析引擎,重点介绍了解析引擎的核心组件ANTLR
;本文继续介绍分片流程中的路由引擎,路由引擎可以说是整个分片流程的核心模块,用户自定义的分片算法都在路由引擎中执行;
开启日志
为了更加清晰详细的查看路由日志,开启SQL_SHOW
功能:
-
引入log4j相关jar,以及log4j.xml配置文件
-
配置
SQL_SHOW
属性为开启:Properties prop = new Properties(); prop.put(ConfigurationPropertyKey.SQL_SHOW.getKey(), true);
路由装饰器
路由引擎的外层包装了一层路由装饰器RouteDecorator
,为什么要这么设计是因为除了我们正常走路由算法的路由引擎,ShardingSphere-JDBC
还提供了读写分离功能,这其实在一定程度上来讲也是路由,而且这两种路由方式是可以叠加的;所有这里提供了一层抽象,实现类包括:
- MasterSlaveRouteDecorator:读写分离路由装饰器;
- ShardingRouteDecorator:分片路由装饰器,内部包含了各种路由引擎;
装饰器可以叠加,所以提供了优先级功能OrderAware
,同时每个装饰器都有对应的规则,大致如下所示:
装饰器-RouteDecorator | 配置-Configuration | 规则-BaseRule | 优先级-Order |
---|---|---|---|
MasterSlaveRouteDecorator | MasterSlaveRuleConfiguration | MasterSlaveRule | 10 |
ShardingRouteDecorator | ShardingRuleConfiguration | ShardingRule | 0 |
根据优先级可以知道首先执行ShardingRouteDecorator
,有了路由结果再执行MasterSlaveRouteDecorator
;部分启动类代码在DataNodeRouter
中如下所示:
private final Map<BaseRule, RouteDecorator> decorators = new LinkedHashMap<>();
private RouteContext executeRoute(final String sql, final List<Object> parameters, final boolean useCache) {
RouteContext result = createRouteContext(sql, parameters, useCache);
for (Entry<BaseRule, RouteDecorator> entry : decorators.entrySet()) {
result = entry.getValue().decorate(result, metaData, entry.getKey(), properties);
}
return result;
}
decorators
会根据用户的配置来决定是否会启动对应的装饰器,可以参考上面的表格;下面按照优先级分别介绍两种装饰器;
分片路由装饰器
经过解析引擎获取到了SQLStatement
,想要做分片路由除了此参数还需要另外一个重要参数分片路由规则ShardingRule
;有了这两个核心参数分片路由大致可以分为以下几步:
- 获取分片条件
ShardingConditions
- 获取具体分片引擎
ShardingRouteEngine
- 执行路由处理,获取路由结果
在详细介绍每一步之前,首先介绍以下几个核心参数RouteContext
、ShardingRule
;
核心参数
重点看一下RouteContext
、ShardingRule
这两个核心参数;
RouteContext
路由上下文参数,主要包含如下几个参数:
public final class RouteContext {
private final SQLStatementContext sqlStatementContext;
private final List<Object> parameters;
private final RouteResult routeResult;
}
- sqlStatementContext:解析引擎获取的
SQLStatement
; - parameters:
PreparedStatement
中设置的参数,如执行insert操作setXxx
代替?
; - routeResult:路由之后用来存放路由结果;
ShardingRule
分片规则,主要参数如下,这个其实和ShardingRuleConfiguration
大同小异,只是重新做了一个包装;
public class ShardingRule implements BaseRule {
private final ShardingRuleConfiguration ruleConfiguration;
private final ShardingDataSourceNames shardingDataSourceNames;
private final Collection<TableRule> tableRules;
private final Collection<BindingTableRule> bindingTableRules;
private final Collection<String> broadcastTables;
private final ShardingStrategy defaultDatabaseShardingStrategy;
private final ShardingStrategy defaultTableShardingStrategy;
private final ShardingKeyGenerator defaultShardingKeyGenerator;
private final Collection<MasterSlaveRule> masterSlaveRules;
private final EncryptRule encryptRule;
- ruleConfiguration:路由规则配置,可以理解为是
ShardingRule
的原始文件; - shardingDataSourceNames:分片的数据源名称;
- tableRules:表路由规则,对应了用户配置的
TableRuleConfiguration
; - bindingTableRules:绑定表配置,分⽚规则⼀致的主表和⼦表;
- broadcastTables:广播表配置,所有的分⽚数据源中都存在的表;
- defaultDatabaseShardingStrategy:默认库分片策略;
- defaultTableShardingStrategy:默认表分片策略;
- defaultShardingKeyGenerator:默认主键生成策略;
- masterSlaveRules:主从规则配置,用来实现读写分离的,可配置一个主表多个从表;
- encryptRule:加密规则配置,提供了对某些敏感数据进行加密的功能;
获取分片条件
在获取具体路由引擎和执行路由操作之前,我们需要获取分片的条件,常见的分片条件主要在Insert语句和Where语句后面;部分获取分片条件的源码如下:
private ShardingConditions getShardingConditions(final List<Object> parameters,
final SQLStatementContext sqlStatementContext, final SchemaMetaData schemaMetaData, final ShardingRule shardingRule) {
if (sqlStatementContext.getSqlStatement() instanceof DMLStatement) {
if (sqlStatementContext instanceof InsertStatementContext) {
return new ShardingConditions(new InsertClauseShardingConditionEngine(shardingRule).createShardingConditions((InsertStatementContext) sqlStatementContext, parameters));
}
return new ShardingConditions(new WhereClauseShardingConditionEngine(shardingRule, schemaMetaData).createShardingConditions(sqlStatementContext, parameters)