ShardingSphere的SQL重写机制竟然用到了这种设计模式
【摘要】 ShardingSphere的SQL重写机制竟然用到了这种设计模式本篇文章源码基于4.0.1版本我们之前在讲ShardingSphere的路由流程的时候,提到所有的路由引擎都是BaseShardingEngine抽象类的实现类,分片流程在它的shard()方法中定义BaseShardingEngine的shard()方法:public SQLRouteResult shard(final ...
ShardingSphere的SQL重写机制竟然用到了这种设计模式
本篇文章源码基于4.0.1版本
我们之前在讲ShardingSphere的路由流程的时候,提到所有的路由引擎都是BaseShardingEngine抽象类的实现类,分片流程在它的shard()方法中定义
BaseShardingEngine的shard()方法:
public SQLRouteResult shard(final String sql, final List<Object> parameters) {
List<Object> clonedParameters = cloneParameters(parameters);
SQLRouteResult result = executeRoute(sql, clonedParameters);
result.getRouteUnits().addAll(HintManager.isDatabaseShardingOnly() ? convert(sql, clonedParameters, result) : rewriteAndConvert(sql, clonedParameters, result));
boolean showSQL = shardingProperties.getValue(ShardingPropertiesConstant.SQL_SHOW);
if (showSQL) {
boolean showSimple = shardingProperties.getValue(ShardingPropertiesConstant.SQL_SIMPLE);
SQLLogger.logSQL(sql, showSimple, result.getSqlStatementContext(), result.getRouteUnits());
}
return result;
}
在分片的过程中,先对参数进行拷贝准备参数,然后执行路由,接下来就是SQL的转换和重写,今天就分析一下它的重写机制
ShardingSphere的重写机制
ShardingSphere的重写机制对应的方法是BaseShardingEngine的rewriteAndConvert()方法:
private Collection<RouteUnit> rewriteAndConvert(final String sql, final List<Object> parameters, final SQLRouteResult sqlRouteResult) {
SQLRewriteContext sqlRewriteContext = new SQLRewriteContext(metaData.getRelationMetas(), sqlRouteResult.getSqlStatementContext(), sql, parameters);
new ShardingSQLRewriteContextDecorator(shardingRule, sqlRouteResult).decorate(sqlRewriteContext);
boolean isQueryWithCipherColumn = shardingProperties.<Boolean>getValue(ShardingPropertiesConstant.QUERY_WITH_CIPHER_COLUMN);
new EncryptSQLRewriteContextDecorator(shardingRule.getEncryptRule(), isQueryWithCipherColumn).decorate(sqlRewriteContext);
sqlRewriteContext.generateSQLTokens();
Collection<RouteUnit> result = new LinkedHashSet<>();
for (RoutingUnit each : sqlRouteResult.getRoutingResult().getRoutingUnits()) {
ShardingSQLRewriteEngine sqlRewriteEngine = new ShardingSQLRewriteEngine(shardingRule, sqlRouteResult.getShardingConditions(), each);
SQLRewriteResult sqlRewriteResult = sqlRewriteEngine.rewrite(sqlRewriteContext);
result.add(new RouteUnit(each.getDataSourceName(), new SQLUnit(sqlRewriteResult.getSql(), sqlRewriteResult.getParameters())));
}
return result;
}
- 构建SQL重写上下文对象
- 构建用于分片的 SQL 重写上下文装饰器对象,对SQL重写上下文对象进行装饰
- 判断加密数据时,是否使用加密列查询。
- 构建用于加密的 SQL 重写上下文装饰器对象,对SQL重写上下文对象进行装饰
- 通过SQL重写上下文生成SQL令牌
- 遍历路由结果的路由单元,创建用于分片的 SQL 重写引擎ShardingSQLRewriteEngine对象,调用rewrite()方法进行重写,然后保存重写的结果并返回,结果包含目标数据库,目标SQL和相关参数。
构建SQL重写上下文对象
构建SQL重写上下文对象的构造方法中添加了移除令牌的SQL 令牌生成器,用来生成移除SQL的SQL令牌
用于分片的 SQL 重写上下文
这里用到了装饰者模式,它的decorate()方法中第一步会判断是否需要参数重写,如果需要就使用GroupedParameterBuilder 补充列名,设置参数值,像插入SQL的主键的自动生成就是通过这个来添加主键列和主键值,主键值通过上一步的路由调用相关的主键生成策略生成后封装到了SQLRouteResult对象中,第二步会添加令牌生成器,ShardingTokenGenerateBuilder的buildSQLTokenGenerators()方法中构建了很多SQL令牌生成器包括生成的键插入列令牌生成器GeneratedKeyInsertColumnTokenGenerator和表令牌生成器TableTokenGenerator
判断是否需要加密列查询
这一块的判断主要是下一步的用于加密的 SQL 重写上下文装饰器作为参数使用
用于加密的 SQL 重写上下文
这里也是装饰者模式的体现,不再细说了
通过SQL重写上下文生成SQL令牌
生成SQL令牌的过程会由具体的令牌生成器类生成
重写SQL
ShardingSQLRewriteEngine的rewrite()方法中调用ShardingSQLBuilder生成SQL,这一块的逻辑在它的父类AbstractSQLBuilder中定义,是模板方法模式的体现,子类需要完成的是getSQLTokenText()方法,也就是获取Sql令牌的文本内容,细说这里,判断SQL令牌是RoutingUnitAware路由单元感知的实例还是LogicAndActualTablesAware逻辑表与实际表感知实例,RoutingUnitAware是实现类是ShardingInsertValuesToken,LogicAndActualTablesAware的实现类有TableToken和IndexToken,TableToken要做的工作就是根据逻辑名获取真实的表名,转化为小写,构建令牌,逻辑表名和真实表名的对应关系BindingTableRule提供了getBindingActualTable()的方法,IndexToken的逻辑实现很简答,这里就不多说了
总结
这篇文章我们以路由流程为入口,详细分析了执行完路由之后的重写SQL的环节,大致流程是创建SQL重写下文对象,然后利用装饰器模式构建用于分片的SQL重写上下文装饰器和用于加密的SQL重写上下文装饰器装饰SQL重写上下文,然后遍历路由结果的路由单元,生成包含目标数据库,目标SQL和相关参数的结果。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)