前言
本章继续分析ShardingJDBC的核心步骤:结果合并。
一、ResultProcessEngine
ResultProcessEngine结果处理引擎,是个标记接口,继承OrderAware接口(SPI相关)。
public interface ResultProcessEngine<T extends BaseRule> extends OrderAware<Class<T>> {
}
它有两个子接口:ResultMergerEngine、ResultDecoratorEngine。
1、ResultMergerEngine&ResultMerger
ResultMergerEngine负责创建ResultMerger,只有一个实现类ShardingResultMergerEngine。
public interface ResultMergerEngine<T extends BaseRule> extends ResultProcessEngine<T> {
ResultMerger newInstance(DatabaseType databaseType, T rule, ConfigurationProperties properties, SQLStatementContext sqlStatementContext);
}
ResultMerger执行结果归并。
public interface ResultMerger {
MergedResult merge(List<QueryResult> queryResults, SQLStatementContext sqlStatementContext, SchemaMetaData schemaMetaData) throws SQLException;
}
2、ResultDecoratorEngine&ResultDecorator
ResultDecorator负责创建ResultDecorator,只有一个实现类EncryptResultDecoratorEngine。
public interface ResultDecoratorEngine<T extends BaseRule> extends ResultProcessEngine<T> {
ResultDecorator newInstance(DatabaseType databaseType, SchemaMetaData schemaMetaData, T rule, ConfigurationProperties properties, SQLStatementContext sqlStatementContext);
}
ResultDecorator针对归并结果做装饰,可以针对QueryResult也可以针对MergedResult。
public interface ResultDecorator {
MergedResult decorate(QueryResult queryResult, SQLStatementContext sqlStatementContext, SchemaMetaData schemaMetaData) throws SQLException;
MergedResult decorate(MergedResult mergedResult, SQLStatementContext sqlStatementContext, SchemaMetaData schemaMetaData) throws SQLException;
}
二、MergeEntry
MergeEntry是执行结果归并的入口。
1、注册ResultProcessEngine
与DataNodeRouter(路由)、SQLRewriteEntry(重写)一样,归并也是通过外部注入BaseRule与处理类ResultProcessEngine的映射关系。
public final class MergeEntry {
// BaseRule - ResultProcessEngine
private final Map<BaseRule, ResultProcessEngine> engines = new LinkedHashMap<>();
public void registerProcessEngine(final BaseRule rule, final ResultProcessEngine processEngine) {
engines.put(rule, processEngine);
}
}
注册入口即MergeEngine,先执行registerMergeDecorator方法,使用SPI机制找到所有ResultProcessEngine,向MergeEntry注册BaseRule对应的ResultProcessEngine。
public final class MergeEngine {
private final Collection<BaseRule> rules;
private final MergeEntry merger;
public MergeEngine(final Collection<BaseRule> rules, final ConfigurationProperties properties, final DatabaseType databaseType, final SchemaMetaData metaData) {
this.rules = rules;
merger = new MergeEntry(databaseType, metaData, properties);
}
public MergedResult merge(final List<QueryResult> queryResults, final SQLStatementContext sqlStatementContext) throws SQLException {
registerMergeDecorator();
return merger.process(queryResults, sqlStatementContext);
}
private void registerMergeDecorator() {
for (Class<? extends ResultProcessEngine> each : OrderedRegistry.getRegisteredClasses(ResultProcessEngine.class)) {
ResultProcessEngine processEngine = createProcessEngine(each);
Class<?> ruleClass = (Class<?>) processEngine.getType();
rules.stream().filter(rule -> rule.getClass() == ruleClass || rule.getClass().getSuperclass() == ruleClass).collect(Collectors.toList())
.forEach(rule -> merger.registerProcessEngine(rule, processEngine));
}
}
private ResultProcessEngine createProcessEngine(final Class<? extends ResultProcessEngine> processEngine) {
return processEngine.newInstance();
}
}
接下来执行MergeEntry的process方法,执行归并。
2、归并
MergeEntry的process方法是归并的主流程。
public MergedResult process(final List<QueryResult> queryResults, final SQLStatementContext sqlStatementContext) throws SQLException {
// 执行BaseRule对应的ResultMergerEngine(目前只有ShardingRule对应的ShardingResultMergerEngine)
// 如果没有BaseRule对应的ResultMergerEngine,这里mergedResult就是空
Optional<MergedResult> mergedResult = merge(queryResults, sqlStatementContext);
Optional<MergedResult> result = mergedResult.isPresent()
// 如果mergedResult不是空(有配置ShardingRuleConfiguration),执行ResultDecoratorEngine装饰MergedResult
? Optional.of(decorate(mergedResult.get(), sqlStatementContext))
// 如果mergedResult是空(比如只配置了EncryptRuleConfiguration),执行ResultDecoratorEngine装饰QueryResult
: decorate(queryResults.get(0), sqlStatementContext);
// 如果结果还是空(比如只配了主从),返回TransparentMergedResult委托第一个QueryResult实现MergedResult
return result.orElseGet(() -> new TransparentMergedResult(queryResults.get(0)));
}
首先找到ResultMergerEngine实例化ResultMerger,执行ResultMerger的merge方法得到MergedResult。
private final DatabaseType databaseType;
private final SchemaMetaData schemaMetaData;
private final ConfigurationProperties properties;
private final Map<BaseRule, ResultProcessEngine> engines = new LinkedHashMap<>();
private Optional<MergedResult> merge(final List<QueryResult> queryResults, final SQLStatementContext sqlStatementContext) throws SQLException {
for (Entry<BaseRule, ResultProcessEngine> entry : engines.entrySet()) {
if (entry.getValue() instanceof ResultMergerEngine) {
// 实例化ResultMerger
ResultMerger resultMerger = ((ResultMergerEngine) entry.getValue()).newInstance(databaseType, entry.getKey(), properties, sqlStatementContext);
// merge
return Optional.of(resultMerger.merge(queryResults, sqlStatementContext, schemaMetaData));
}
}
return Optional.empty();
}
接下来判断merge方法返回结果MergedResult是否为空,如果为空,执行ResultDecorator对QueryResult装饰为MergedResult,如果中间转换为MergedResult成功,还会对MergedResult做二次装饰。
// 对QueryResult做装饰 转换为MergedResult
// 如果中间转换为MergedResult成功,还会对MergedResult做二次装饰
private Optional<MergedResult> decorate(final QueryResult queryResult, final SQLStatementContext sqlStatementContext) throws SQLException {
MergedResult result = null;
for (Entry<BaseRule, ResultProcessEngine> entry : engines.entrySet()) {
if (entry.getValue() instanceof ResultDecoratorEngine) {
ResultDecorator resultDecorator = ((ResultDecoratorEngine) entry.getValue()).newInstance(databaseType, schemaMetaData, entry.getKey(), properties, sqlStatementContext);
// 第一次进来时result为null,对入参queryResult装饰
// 后续进来result不为null,对result装饰
result = null == result ? resultDecorator.decorate(queryResult, sqlStatementContext, schemaMetaData) : resultDecorator.decorate(result, sqlStatementContext, schemaMetaData);
}
}
return Optional.ofNullable(result);
}
MergedResult如果不为空,执行ResultDecorator对MergedResult做二次装饰。
// 对MergedResult做二次装饰
private MergedResult decorate(final MergedResult mergedResult, final SQLStatementContext sqlStatementContext) throws SQLException {
MergedResult result = null;
for (Entry<BaseRule, ResultProcessEngine> entry : engines.entrySet()) {
if (entry.getValue() instanceof ResultDecoratorEngine) {
ResultDecorator resultDecorator = ((ResultDecoratorEngine) entry.getValue()).newInstance(databaseType, schemaMetaData, entry.getKey(), properties, sqlStatementContext);
// 第一次进来时result为null,对入参mergedResult装饰
// 后续进来result不为null,对result装饰
result = null == result ? resultDecorator.decorate(mergedResult, sqlStatementContext, schemaMetaData) : resultDecorator.decorate(result, sqlStatementContext, schemaMetaData);
}
}
return null == result ? mergedResult : result;
}
process的兜底方案是返回一个TransparentMergedResult,用第一个QueryResult,实现所有MergedResult接口方法。
三、ShardingResultMergerEngine
ShardingResultMergerEngine的newInstance方法,根据sql的类型,创建不同的ResultMerger,比如DQL会创建ShardingDQLResultMerger,兜底创建TransparentResultMerger。
public final class ShardingResultMergerEngine implements ResultMergerEngine<ShardingRule> {
@Override
public ResultMerger newInstance(final DatabaseType databaseType, final ShardingRule shardingRule, final ConfigurationProperties properties, final SQLStatementContext sqlStatementContext) {
if (sqlStatementContext instanceof SelectStatementContext) {
return new ShardingDQLResultMerger(databaseType);
}
if (sqlStatementContext.getSqlStatement() instanceof DALStatement) {
return new ShardingDALResultMerger(shardingRule);
}
return new TransparentResultMerger();
}
@Override
public int getOrder() {
return 0;
}
@Override
public Class<ShardingRule> getType() {
return ShardingRule.class;
}
}
四、ShardingDQLResultMerger
ShardingDQLResultMerger用于处理查询语句。merge方法针对不同的情况new了不同的MergedResult。首先如果结果集个数只有一个,那么使用IteratorStreamMergedResult。接下来创建字段别名与字段下标索引的映射关系。
@RequiredArgsConstructor
public final class ShardingDQLResultMerger implements ResultMerger {
private final DatabaseType databaseType;
@Override
public MergedResult merge(final List<QueryResult> queryResults, final SQLStatementContext sqlStatementContext, final SchemaMetaData schemaMetaData) throws SQLException {
// 如果只有一个结果集,返回IteratorStreamMergedResult
if (1 == queryResults.size()) {
return new IteratorStreamMergedResult(queryResults);
}
// 创建字段别名与字段下标索引的映射关系
Map<String, Integer> columnLabelIndexMap = getColumnLabelIndexMap(queryResults.get(0));
SelectStatementContext selectStatementContext = (SelectStatementContext) sqlStatementContext;
selectStatementContext.setIndexes(columnLabelIndexMap);
// 创建不同的MergedResult
MergedResult mergedResult = build(queryResults, selectStatementContext, columnLabelIndexMap, schemaMetaData);
// 对分页查询的MergedResult做一次装饰
return decorate(queryResults, selectStatementContext, mergedResult);
}
}
build方法。如果分组或聚合或distinct,根据isSameGroupByAndOrderByItems,走GroupByStreamMergedResult或GroupByMemoryMergedResult;如果存在排序,走OrderByStreamMergedResult;兜底返回IteratorStreamMergedResult。
private MergedResult build(final List<QueryResult> queryResults, final SelectStatementContext selectStatementContext,
final Map<String, Integer> columnLabelIndexMap, final SchemaMetaData schemaMetaData) throws SQLException {
// 存在 分组或聚合
if (isNeedProcessGroupBy(selectStatementContext)) {
return getGroupByMergedResult(queryResults, selectStatementContext, columnLabelIndexMap, schemaMetaData);
}
// 存在 distinct
if (isNeedProcessDistinctRow(selectStatementContext)) {
setGroupByForDistinctRow(selectStatementContext);
return getGroupByMergedResult(queryResults, selectStatementContext, columnLabelIndexMap, schemaMetaData);
}
// 存在 排序
if (isNeedProcessOrderBy(selectStatementContext)) {
return new OrderByStreamMergedResult(queryResults, selectStatementContext, schemaMetaData);
}
return new IteratorStreamMergedResult(queryResults);
}
// 如果isSameGroupByAndOrderByItems,走流式归并结果;否则走内存归并结果。
private MergedResult getGroupByMergedResult(final List<QueryResult> queryResults, final SelectStatementContext selectStatementContext,
final Map<String, Integer> columnLabelIndexMap, final SchemaMetaData schemaMetaData) throws SQLException {
return selectStatementContext.isSameGroupByAndOrderByItems()
? new GroupByStreamMergedResult(columnLabelIndexMap, queryResults, selectStatementContext, schemaMetaData)
: new GroupByMemoryMergedResult(queryResults, selectStatementContext, schemaMetaData);
}
经过build方法首次获取到MergedResult合并结果后,如果存在分页,会根据db类型做一次装饰。
private MergedResult decorate(final List<QueryResult> queryResults, final SelectStatementContext selectStatementContext, final MergedResult mergedResult) throws SQLException {
PaginationContext paginationContext = selectStatementContext.getPaginationContext();
if (!paginationContext.isHasPagination() || 1 == queryResults.size()) {
return mergedResult;
}
String trunkDatabaseName = DatabaseTypes.getTrunkDatabaseType(databaseType.getName()).getName();
if ("MySQL".equals(trunkDatabaseName) || "PostgreSQL".equals(trunkDatabaseName)) {
return new LimitDecoratorMergedResult(mergedResult, paginationContext);
}
if ("Oracle".equals(trunkDatabaseName)) {
return new RowNumberDecoratorMergedResult(mergedResult, paginationContext);
}
if ("SQLServer".equals(trunkDatabaseName)) {
return new TopAndRowNumberDecoratorMergedResult(mergedResult, paginationContext);
}
return mergedResult;
}
五、EncryptResultDecoratorEngine与EncryptDQLResultDecorator
EncryptResultDecoratorEngine是ResultDecoratorEngine的唯一实现类,创建加密结果装饰器。
public final class EncryptResultDecoratorEngine implements ResultDecoratorEngine<EncryptRule> {
@Override
public ResultDecorator newInstance(final DatabaseType databaseType, final SchemaMetaData schemaMetaData,
final EncryptRule encryptRule, final ConfigurationProperties properties, final SQLStatementContext sqlStatementContext) {
if (sqlStatementContext instanceof SelectStatementContext) {
return new EncryptDQLResultDecorator(
new EncryptorMetaData(schemaMetaData, encryptRule, (SelectStatementContext) sqlStatementContext), properties.<Boolean>getValue(ConfigurationPropertyKey.QUERY_WITH_CIPHER_COLUMN));
}
if (sqlStatementContext.getSqlStatement() instanceof DALStatement) {
return new EncryptDALResultDecorator();
}
return new TransparentResultDecorator();
}
@Override
public int getOrder() {
return 20;
}
@Override
public Class<EncryptRule> getType() {
return EncryptRule.class;
}
}
EncryptDQLResultDecorator两个decorate方法都是创建EncryptMergedResult。
@RequiredArgsConstructor
public final class EncryptDQLResultDecorator implements ResultDecorator {
private final EncryptorMetaData encryptorMetaData;
private final boolean queryWithCipherColumn;
@Override
public MergedResult decorate(final QueryResult queryResult, final SQLStatementContext sqlStatementContext, final SchemaMetaData schemaMetaData) {
return new EncryptMergedResult(encryptorMetaData, new TransparentMergedResult(queryResult), queryWithCipherColumn);
}
@Override
public MergedResult decorate(final MergedResult mergedResult, final SQLStatementContext sqlStatementContext, final SchemaMetaData schemaMetaData) {
return new EncryptMergedResult(encryptorMetaData, mergedResult, queryWithCipherColumn);
}
}
EncryptMergedResult重点是getValue方法。
@RequiredArgsConstructor
public final class EncryptMergedResult implements MergedResult {
private final EncryptorMetaData metaData;
private final MergedResult mergedResult;
private final boolean queryWithCipherColumn;
@Override
public Object getValue(final int columnIndex, final Class<?> type) throws SQLException {
// query.with.cipher.column 是否启用加密字段
if (!queryWithCipherColumn) {
return mergedResult.getValue(columnIndex, type);
}
// 找到加解密器
Optional<Encryptor> encryptor = metaData.findEncryptor(columnIndex);
if (!encryptor.isPresent()) {
return mergedResult.getValue(columnIndex, type);
}
// 密文
String ciphertext = (String) mergedResult.getValue(columnIndex, String.class);
// 解密
return null == ciphertext ? null : encryptor.get().decrypt(ciphertext);
}
}
总结
- ResultMergerEngine创建ResultMerger,ResultMerger只有一个merge方法执行结果归并。
- ResultDecorator创建ResultDecorator,ResultDecorator针对归并结果做装饰,可以针对QueryResult也可以针对MergedResult。
- MergeEntry的process方法是结果归并的主流程入口。
- ShardingResultMergerEngine是ResultMergerEngine的唯一实现类,根据sql的类型,创建不同的ResultMerger。
- ShardingDQLResultMerger处理查询语句结果合并。merge方法针对不同情况创建不同MergedResult。
- 如果结果集个数只有一个,使用IteratorStreamMergedResult。
- 如果存在分组、聚合、去重,使用GroupByStreamMergedResult或GroupByMemoryMergedResult。
- 如果存在排序,使用OrderByStreamMergedResult。
- 兜底使用IteratorStreamMergedResult。
- 针对分页查询,ShardingDQLResultMerger在得到MergedResult之后会做一次装饰。MySQL使用LimitDecoratorMergedResult装饰上面得到的MergedResult。
- EncryptResultDecoratorEngine是ResultDecoratorEngine的唯一实现类,创建加密结果装饰器EncryptDQLResultDecorator。EncryptDQLResultDecorator会对查询结果做解密。