Sharding-JDBC源码解析(一)整体流程-CSDN博客
Sharding-JDBC源码解析(二)SQL解析-CSDN博客
Sharding-JDBC源码解析(三)SQL路由-CSDN博客
Sharding-JDBC源码解析(四)SQL改写-CSDN博客
Sharding-JDBC源码解析(五)SQL执行-CSDN博客
Sharding-JDBC源码解析(六)结果归并-CSDN博客
目录
一、整体概述
为什么需要sql改写?这是由于用户写的sql都是面向逻辑库与逻辑表,并不能够直接在真实的数据库中执行,sql 改写用于将逻辑 sql 改写为在真实数据库中可以正确执行的 sql。 它包括正确性改写和优化改写两部分。
二、详细流程
下列的代码部分删减掉非核心的部分,部分直接以伪代码或文字的方式描述,需要详细的信息可以自行参照方法入口去阅读。
1.整体流程
重写的整体流程也是使用了装饰器模式,核心代码类位于SQLRewriteEntry,主要分为两部分,第一部分是在构造函数中去加载需要使用到的装饰器,主要使用到的只有ShardingSQLRewriteContextDecorator(未使用到数据加密功能的情况下不会涉及到另一个装饰器EncryptSQLRewriteContextDecorator),第二部分则是在rewrite方法中使用装饰器链去对sql进行改写。
SQLRewriteEntry使用了装饰器模式,在构造函数中会去对装饰器进行加载
public SQLRewriteEntry(final ShardingSphereSchema schema, final ConfigurationProperties props, final Collection<ShardingSphereRule> rules) {
decorators = OrderedSPIRegistry.getRegisteredServices(SQLRewriteContextDecorator.class, rules);
}
改写的过程在ShardingSQLRewriteContextDecorator的decorate方法中,流程上是先对sql的参数进行改写,再对sql的语法进行改写。后续主要对分片改写器进行介绍。
private void decorate(final Map<ShardingSphereRule, SQLRewriteContextDecorator> decorators, final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {
// 遍历装饰器链,对sql进行改写。
decorators.forEach((key, value) -> value.decorate(key, props, sqlRewriteContext, routeContext));
}
2.改写器
2-1.分片改写器
public void decorate(final ShardingRule shardingRule, final ConfigurationProperties props, final SQLRewriteContext sqlRewriteContext, final RouteContext routeContext) {
if (routeContext.isFederated()) {
return;
}
// 获取参数重写器 判断是否需要对参数进行重写 比如sql携带分页信息,就需要对分页的参数进行正确的重写
// ParameterRewriter 处理的是参数化查询中的参数重写
for (ParameterRewriter each : new ShardingParameterRewriterBuilder(shardingRule, routeContext).getParameterRewriters(sqlRewriteContext.getSchema())) {
if (!sqlRewriteContext.getParameters().isEmpty() && each.isNeedRewrite(sqlRewriteContext.getSqlStatementContext())) {
each.rewrite(sqlRewriteContext.getParameterBuilder(), sqlRewriteContext.getSqlStatementContext(), sqlRewriteContext.getParameters());
}
}
// 结合当前sql加载需要的SQLTokenGenerator, 然后通过SQLTokenGenerator对sql进行改写
// SQLTokenGenerator 处理的是对 SQL 语句的结构性改写
sqlRewriteContext.addSQLTokenGenerators(new ShardingTokenGenerateBuilder(shardingRule, routeContext).getSQLTokenGenerators());
}
分页改写
对于分页改写的原理参考官网改写引擎 :: ShardingSphere
代码位于ShardingPaginationParameterRewriter#rewrite, 逻辑比较简单,新offset=0,新limit=旧offset + 旧limit。
排序改写
作用于那些没有指明order by的sql进行改写,默认会使用主键升序的方式。
-- 主键为id
-- 原sql
select * from tb;
-- 改写后
select * from tb order by id asc;