当前位置: 首页 > news >正文

【源码】Sharding-JDBC源码分析之SQL中分片键路由ShardingSQLRouter的原理

 Sharding-JDBC系列

1、Sharding-JDBC分库分表的基本使用

2、Sharding-JDBC分库分表之SpringBoot分片策略

3、Sharding-JDBC分库分表之SpringBoot主从配置

4、SpringBoot集成Sharding-JDBC-5.3.0分库分表

5、SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表

6、【源码】Sharding-JDBC源码分析之JDBC

7、【源码】Sharding-JDBC源码分析之SPI机制

8、【源码】Sharding-JDBC源码分析之Yaml分片配置文件解析原理

9、【源码】Sharding-JDBC源码分析之Yaml分片配置原理(一)

10、【源码】Sharding-JDBC源码分析之Yaml分片配置原理(二)

11、【源码】Sharding-JDBC源码分析之Yaml分片配置转换原理

12、【源码】Sharding-JDBC源码分析之ShardingSphereDataSource的创建原理

13、【源码】Sharding-JDBC源码分析之ContextManager创建中mode分片配置信息的持久化存储的原理

14、【源码】Sharding-JDBC源码分析之ContextManager创建中ShardingSphereDatabase的创建原理

15、【源码】Sharding-JDBC源码分析之分片规则生成器DatabaseRuleBuilder实现规则配置到规则对象的生成原理

16、【源码】Sharding-JDBC源码分析之配置数据库定义的表的元数据解析原理

17、【源码】Sharding-JDBC源码分析之ShardingSphereConnection的创建原理

18、【源码】Sharding-JDBC源码分析之ShardingSpherePreparedStatement的创建原理

19、【源码】Sharding-JDBC源码分析之Sql解析的原理

20、【源码】Sharding-JDBC源码分析之SQL路由及SingleSQLRouter单表路由

21、【源码】Sharding-JDBC源码分析之SQL中分片键路由ShardingSQLRouter的原理

前言

ShardingSphere透明的为Java应用程序提供了数据库分片功能,只需配置好分片规则,无需关心底层的数据库分片细节。ShardingSphere框架根据配置好的分片规则,自动路由到实际操作的数据库、表中。本文从源码的角度分析 SQL 路由中的分片路由器ShardingSQLRouter的实现原理。

ShardingSpherePreparedStatement回顾

在【源码】Sharding-JDBC源码分析之SQL路由及SingleSQLRouter单表路由-CSDN博客中分析在执行SQL语句前,会进行SQL路由,创建RouteContext对象,在RouteContext路由上下文对象中,包含了SQL真正执行的数据源、逻辑表及真实表的映射。如果是DML操作,且配置了分片键,则ShardingSQLRouter分片路由器会第一个执行。

ShardingSQLRouter

如果没有通过提示语指定路由的数据源,则从SPI获取路由器之后,优先执行ShardingSQLRouter分片路由器,即执行路由器的createRouteContext()方法。在该类中,对应的decorateRouteContext()方法为空方法。

ShardingSQLRouter的源码如下:

package org.apache.shardingsphere.sharding.route.engine;/*** 分片SQL路由器*/
public final class ShardingSQLRouter implements SQLRouter<ShardingRule> {/*** 创建路由上下文* @param queryContext 查询上下文* @param database 数据库信息* @param rule 分片规则* @param props 配置的属性* @param connectionContext 连接上下文* @return*/@SuppressWarnings({"rawtypes", "unchecked"})@Overridepublic RouteContext createRouteContext(final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingRule rule,final ConfigurationProperties props, final ConnectionContext connectionContext) {// 获取对应数据库、对应查询类型的SQL语句对象SQLStatement sqlStatement = queryContext.getSqlStatementContext().getSqlStatement();// 解析,获取分片条件ShardingConditions shardingConditions = createShardingConditions(queryContext, database, rule);// 获取分片语句校验器,查询语句返回空Optional<ShardingStatementValidator> validator = ShardingStatementValidatorFactory.newInstance(sqlStatement, shardingConditions);// 校验validator.ifPresent(optional -> optional.preValidate(rule, queryContext.getSqlStatementContext(), queryContext.getParameters(), database, props));if (sqlStatement instanceof DMLStatement && shardingConditions.isNeedMerge()) {shardingConditions.merge();}// 创建路由引擎对象,执行路由,获取路由上下文RouteContext result = ShardingRouteEngineFactory.newInstance(rule, database, queryContext, shardingConditions, props, connectionContext).route(rule);// 校验validator.ifPresent(optional -> optional.postValidate(rule, queryContext.getSqlStatementContext(), queryContext.getHintValueContext(), queryContext.getParameters(), database, props, result));return result;}/*** 创建分片条件对象* @param queryContext 查询上下文* @param database 数据库信息* @param rule 分片规则* @return*/@SuppressWarnings({"rawtypes", "unchecked"})private ShardingConditions createShardingConditions(final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingRule rule) {List<ShardingCondition> shardingConditions;// 如果SQL操作是DML || 游标if (queryContext.getSqlStatementContext().getSqlStatement() instanceof DMLStatement || queryContext.getSqlStatementContext() instanceof CursorAvailable) {// 创建分片条件引擎的新实例。通过SPI获取,默认返回DefaultShardingConditionEngineShardingConditionEngine shardingConditionEngine = ShardingConditionEngineFactory.createShardingConditionEngine(database, rule);// 通过引擎创建分片条件shardingConditions = shardingConditionEngine.createShardingConditions(queryContext.getSqlStatementContext(), queryContext.getParameters());} else {shardingConditions = Collections.emptyList();}// 创建分片条件集合对象return new ShardingConditions(shardingConditions, queryContext.getSqlStatementContext(), rule);}@Overridepublic void decorateRouteContext(final RouteContext routeContext, final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingRule rule,final ConfigurationProperties props, final ConnectionContext connectionContext) {// TODO}@Overridepublic int getOrder() {return ShardingOrder.ORDER;}@Overridepublic Class<ShardingRule> getTypeClass() {return ShardingRule.class;}
}

3.1 createRouteContext()

在createRouteContext()方法中,主要执行如下:

1)获取SQL语句对象;

2)调用createShardingConditions()方法,解析,获取分片条件集合对象ShardingConditions;

2.1)ShardingConditions包含ShardingCondition集合、sql语句对象及分片规则对象;

2.2)每个分片键对应一个ShardingCondition;

2.3)ShardingCondition中存放分片键的信息,包含分片键的下标、列名、表名、分片的值;

2.4)分片的值主要为两种类型,一种是固定值,用于表示 =、in;另一种为区间值,用于表示 >、< 等区间条件;

3)安全性校验;

4)对于DML语句,如果需要条件合并,则进行条件合并;

5)调用ShardingRouteEngineFactory.newInstance(),创建分片路由引擎对象,执行route()路由方法,获取路由上下文;

5.1)通过ShardingRouteEngineFactory.newInstance(),获取分片路由引擎。对于DML语句的普通分片规则,返回ShardingStandardRoutingEngine对象;

5.2)在ShardingStandardRoutingEngine的route()方法中,根据配置的规则,创建对应的分片策略,执行对应doSharding()方法,传入参数值,获取真正执行的数据库、表信息DataNode;

5.3)根据DataNode,创建路由单元,保存到新创建的RouteContext对象中;

6)安全性校验;

7)返回创建的路由上下文;

3.2 createShardingConditions()

在createShardingConditions()方法中,执行如下:

1)如果SQL操作是DML语句 || 游标类型的语句,则获取分片条件引擎对象,默认为DefaultShardingConditionEngine,执行DefaultShardingConditionEngine的createShardingConditions()方法,创建ShardingCondition集合;

1.1)SQL语句中涉及分片键的有两种类型,一种为插入语句,另一种带where的语句。插入语句的分片键在插入的值中,其他类型的语句分片键在where条件中;

1.2)如果是插入语句,则通过InsertClauseShardingConditionEngine创建ShardingCondition集合;

1.3)其他类型语句,则通过WhereClauseShardingConditionEngine创建ShardingCondition集合;

2)否则不支持分片规则,ShardingCondition集合为空;

3)创建一个ShardingConditions对象,传入上面获取的ShardingCondition集合;

WhereClauseShardingConditionEngine

WhereClauseShardingConditionEngine为从 where 条件中解析出ShardingCondition分片条件的引擎。在该类中,通过解析SQL语句中的where条件部分,结合配置的分片规则,从中找出符合条件的分片键,以及分片键对应的值。

WhereClauseShardingConditionEngine的源码如下:

package org.apache.shardingsphere.sharding.route.engine.condition.engine.impl;/*** where分片条件引擎*/
@RequiredArgsConstructor
public final class WhereClauseShardingConditionEngine {// 分片规则private final ShardingRule shardingRule;// 数据库信息private final ShardingSphereDatabase database;/*** 创建分片条件,每个分片键对应一个ShardingCondition* @param sqlStatementContext* @param params sql语句中的参数值* @return*/public List<ShardingCondition> createShardingConditions(final SQLStatementContext<?> sqlStatementContext, final List<Object> params) {if (!(sqlStatementContext instanceof WhereAvailable)) {return Collections.emptyList();}// 获取where中用到的列,包括子查询Collection<ColumnSegment> columnSegments = ((WhereAvailable) sqlStatementContext).getColumnSegments();// 获取默认的schema的名称。默认为databaseName,即logic_dbString defaultSchemaName = DatabaseTypeEngine.getDefaultSchemaName(sqlStatementContext.getDatabaseType(), database.getName());// 获取schemaShardingSphereSchema schema = sqlStatementContext.getTablesContext().getSchemaName().map(database::getSchema).orElseGet(() -> database.getSchema(defaultSchemaName));// key:列名;value为表名Map<String, String> columnExpressionTableNames = sqlStatementContext.getTablesContext().findTableNamesByColumnSegment(columnSegments, schema);List<ShardingCondition> result = new ArrayList<>();for (WhereSegment each : ((WhereAvailable) sqlStatementContext).getWhereSegments()) {// each.getExpr()返回where条件中的二元运算等表达式,如BinaryOperationExpression// createShardingConditions():解析条件表达式中的分片键ShardingCondition对象result.addAll(createShardingConditions(each.getExpr(), params, columnExpressionTableNames));}return result;}/*** 从where表达式中创建分片条件对象。* 解析条件表达式中的分片键,* 1)如果是一个or条件,前后都有分片键,则创建两个ShardingCondition;* 2)如果是 and 条件,最多创建一个 ShardingCondition;* @param expression where条件中的某个表达式* @param params 参数值* @param columnExpressionTableNames* @return*/private Collection<ShardingCondition> createShardingConditions(final ExpressionSegment expression, final List<Object> params, final Map<String, String> columnExpressionTableNames) {// 获取And的谓词。// 小于等于1个and,创建一个AndPredicate。一个or创建两个AndPredicate。多个and创建一个AndPredicate,其中的predicates包含多个Collection<AndPredicate> andPredicates = ExpressionExtractUtil.getAndPredicates(expression);Collection<ShardingCondition> result = new LinkedList<>();for (AndPredicate each : andPredicates) {// 从谓词中创建分片条件值Map。key为对应的列,value为对应列的分片值对象ShardingConditionValueMap<Column, Collection<ShardingConditionValue>> shardingConditionValues = createShardingConditionValueMap(each.getPredicates(), params, columnExpressionTableNames);// 如果没有分片键,则返回空if (shardingConditionValues.isEmpty()) {return Collections.emptyList();}// 创建分片条件。一个And谓词一个ShardingCondition对象ShardingCondition shardingCondition = createShardingCondition(shardingConditionValues);// TODO remove startIndex when federation has perfect support for subqueryshardingCondition.setStartIndex(expression.getStartIndex());result.add(shardingCondition);}return result;}/*** 从谓词中创建分片条件值Map。key为对应的列,value为对应列的分片值对象ShardingConditionValue* @param predicates 条件中的谓词,如BinaryOperationExpression等* @param params 传入的参数* @param columnTableNames 列及对应表的Map* @return*/private Map<Column, Collection<ShardingConditionValue>> createShardingConditionValueMap(final Collection<ExpressionSegment> predicates,final List<Object> params, final Map<String, String> columnTableNames) {Map<Column, Collection<ShardingConditionValue>> result = new HashMap<>(predicates.size(), 1);// 遍历谓词的表达式for (ExpressionSegment each : predicates) {// 从谓词表达式部分中提取column部分for (ColumnSegment columnSegment : ColumnExtractor.extract(each)) {// 获取列对应的表Optional<String> tableName = Optional.ofNullable(columnTableNames.get(columnSegment.getExpression()));// 从列对应的表中查找配置的分片策略,如果配置的分片策略使用了对应columnName,则返回columnName;否则返回空Optional<String> shardingColumn = tableName.flatMap(optional -> shardingRule.findShardingColumn(columnSegment.getIdentifier().getValue(), optional));// 如果对应列没有配置分片策略,则跳过if (!tableName.isPresent() || !shardingColumn.isPresent()) {continue;}Column column = new Column(shardingColumn.get(), tableName.get());// 创建分片条件值,不同的表达式,场景不同的值。如 =、in,创建ListShardingConditionValue;>、< 等表达式,创建RangeShardingConditionValueOptional<ShardingConditionValue> shardingConditionValue = ConditionValueGeneratorFactory.generate(each, column, params);if (!shardingConditionValue.isPresent()) {continue;}result.computeIfAbsent(column, unused -> new LinkedList<>()).add(shardingConditionValue.get());}}return result;}/*** 创建分片条件对象* @param shardingConditionValues* @return*/private ShardingCondition createShardingCondition(final Map<Column, Collection<ShardingConditionValue>> shardingConditionValues) {ShardingCondition result = new ShardingCondition();for (Entry<Column, Collection<ShardingConditionValue>> entry : shardingConditionValues.entrySet()) {try {// 同一个列的多个分片条件值合并为一个ShardingConditionValue shardingConditionValue = mergeShardingConditionValues(entry.getKey(), entry.getValue());if (shardingConditionValue instanceof AlwaysFalseShardingConditionValue) {return new AlwaysFalseShardingCondition();}result.getValues().add(shardingConditionValue);} catch (final ClassCastException ex) {throw new ShardingValueDataTypeException(entry.getKey());}}return result;}/*** 同一个谓词中的同一个列的多个分片条件值合并为一个* @param column* @param shardingConditionValues* @return*/@SuppressWarnings({"unchecked", "rawtypes"})private ShardingConditionValue mergeShardingConditionValues(final Column column, final Collection<ShardingConditionValue> shardingConditionValues) {Collection<Comparable<?>> listValue = null;Range<Comparable<?>> rangeValue = null;Set<Integer> parameterMarkerIndexes = new HashSet<>();for (ShardingConditionValue each : shardingConditionValues) {// 添加下标parameterMarkerIndexes.addAll(each.getParameterMarkerIndexes());// =、in 的处理if (each instanceof ListShardingConditionValue) {// 获取两个Collection集合的交集// 对于确定的值,如age = 15 and age in (15, 20, 21),则最终只能是查询出age = 15的记录,// 所以此处要进行集合的交集运算[15]和[15, 20, 21],结果为15listValue = mergeListShardingValues(((ListShardingConditionValue) each).getValues(), listValue);// 如果没有交集,则返回falseif (listValue.isEmpty()) {return new AlwaysFalseShardingConditionValue();}} else if (each instanceof RangeShardingConditionValue) { // 区间值的处理try {// 值合并rangeValue = mergeRangeShardingValues(((RangeShardingConditionValue) each).getValueRange(), rangeValue);} catch (final IllegalArgumentException ex) {return new AlwaysFalseShardingConditionValue();}}}if (null == listValue) {return new RangeShardingConditionValue<>(column.getName(), column.getTableName(), rangeValue, new ArrayList<>(parameterMarkerIndexes));}if (null == rangeValue) {return new ListShardingConditionValue<>(column.getName(), column.getTableName(), listValue, new ArrayList<>(parameterMarkerIndexes));}listValue = mergeListAndRangeShardingValues(listValue, rangeValue);return listValue.isEmpty() ? new AlwaysFalseShardingConditionValue(): new ListShardingConditionValue<>(column.getName(), column.getTableName(), listValue, new ArrayList<>(parameterMarkerIndexes));}/*** 保留value1和value2交集的值* @param value1* @param value2* @return*/private Collection<Comparable<?>> mergeListShardingValues(final Collection<Comparable<?>> value1, final Collection<Comparable<?>> value2) {if (null == value2) {return value1;}// 保留value1和value2交集的值value1.retainAll(value2);return value1;}/*** 整合区间值* @param value1* @param value2* @return*/private Range<Comparable<?>> mergeRangeShardingValues(final Range<Comparable<?>> value1, final Range<Comparable<?>> value2) {return null == value2 ? value1 : SafeNumberOperationUtil.safeIntersection(value1, value2);}private Collection<Comparable<?>> mergeListAndRangeShardingValues(final Collection<Comparable<?>> listValue, final Range<Comparable<?>> rangeValue) {Collection<Comparable<?>> result = new LinkedList<>();for (Comparable<?> each : listValue) {if (SafeNumberOperationUtil.safeContains(rangeValue, each)) {result.add(each);}}return result;}
}

在createShardingConditions()方法中,主要执行如下:

1)获取where中用到的列,包括子查询部分;

2)获取默认的schema的名称。默认为databaseName,即logic_db;

3)获取列信息,为Map对象,key:列名;value为表名;

4)遍历查询语句的where部分,查询where部分中的分片键,创建ShardingCondition对象;

4.1)从where部分的表达式中获取AndPredicate谓词;

4.2)遍历AndPredicate谓词,每个谓词根据其中是否包含配置的分片键,以及值类型,创建ShardingCondition对象;

4.3)ShardingCondition对象中保存ShardingConditionValue集合。ShardingConditionValue包含了分片键、所属的表、值;

4.4)ShardingConditionValue主要包含两种类型:ListShardingConditionValue(确定的值,如 =、in 的条件)、RangeShardingConditionValue(区间值,如 > 、>= 等);

where部分解析的大体流程如下:

ShardingStandardRoutingEngine

在ShardingSQLRouter的createRouteContext()方法中,通过ShardingRouteEngineFactory.newInstance(),获取分片路由引擎。对于DML语句的普通分片规则,返回ShardingStandardRoutingEngine对象。

package org.apache.shardingsphere.sharding.route.engine.type.standard;/*** 标准分片路由引擎*/
public final class ShardingStandardRoutingEngine implements ShardingRouteEngine {// 逻辑表。有分片键的表或语句中的第一个表private final String logicTableName;// 分片键的分片条件信息对象private final ShardingConditions shardingConditions;// sql语句private final SQLStatementContext<?> sqlStatementContext;// 配置的propsprivate final ConfigurationProperties props;// SQl 操作的涉及的分片数据节点集合private final Collection<Collection<DataNode>> originalDataNodes = new LinkedList<>();// SQL 语句中的提示提取器private final SQLHintExtractor sqlHintExtractor;public ShardingStandardRoutingEngine(final String logicTableName, final ShardingConditions shardingConditions, final SQLStatementContext<?> sqlStatementContext,final HintValueContext hintValueContext, final ConfigurationProperties props) {this.logicTableName = logicTableName;this.shardingConditions = shardingConditions;this.sqlStatementContext = sqlStatementContext;this.props = props;this.sqlHintExtractor = new SQLHintExtractor(sqlStatementContext.getSqlStatement(), hintValueContext);}/*** 创建路由上下文* @param shardingRule sharding rule* @return*/@Overridepublic RouteContext route(final ShardingRule shardingRule) {RouteContext result = new RouteContext();// 获取当前sql分片条件对应的操作的数据节点。(操作的数据库及表)Collection<DataNode> dataNodes = getDataNodes(shardingRule, shardingRule.getTableRule(logicTableName));result.getOriginalDataNodes().addAll(originalDataNodes);for (DataNode each : dataNodes) {result.getRouteUnits().add(new RouteUnit(new RouteMapper(each.getDataSourceName(), each.getDataSourceName()), Collections.singleton(new RouteMapper(logicTableName, each.getTableName()))));}return result;}/*** 获取数据节点* @param shardingRule* @param tableRule* @return*/private Collection<DataNode> getDataNodes(final ShardingRule shardingRule, final TableRule tableRule) {// 创建数据源分片算法对象ShardingStrategy databaseShardingStrategy = createShardingStrategy(shardingRule.getDatabaseShardingStrategyConfiguration(tableRule),shardingRule.getShardingAlgorithms(), shardingRule.getDefaultShardingColumn());// 创建表分片算法对象ShardingStrategy tableShardingStrategy = createShardingStrategy(shardingRule.getTableShardingStrategyConfiguration(tableRule),shardingRule.getShardingAlgorithms(), shardingRule.getDefaultShardingColumn());// 是否数据源和表规则都是Hint策略if (isRoutingByHint(shardingRule, tableRule)) {return routeByHint(tableRule, databaseShardingStrategy, tableShardingStrategy);}// 是否数据源和表规则都不是Hint策略if (isRoutingByShardingConditions(shardingRule, tableRule)) {return routeByShardingConditions(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy);}// 混合策略return routeByMixedConditions(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy);}/*** 是否为数据源和表规则都是Hint策略* @param shardingRule* @param tableRule* @return*/private boolean isRoutingByHint(final ShardingRule shardingRule, final TableRule tableRule) {return shardingRule.getDatabaseShardingStrategyConfiguration(tableRule) instanceof HintShardingStrategyConfiguration&& shardingRule.getTableShardingStrategyConfiguration(tableRule) instanceof HintShardingStrategyConfiguration;}/*** 判断sql的hint中是否包含了sql语句中的表* @return*/private boolean isRoutingBySQLHint() {Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();for (String each : tableNames) {if (sqlHintExtractor.containsHintShardingValue(each)) {return true;}}return false;}/*** Hint的路由* @param tableRule* @param databaseShardingStrategy* @param tableShardingStrategy* @return*/private Collection<DataNode> routeByHint(final TableRule tableRule, final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {return route0(tableRule, databaseShardingStrategy, getDatabaseShardingValuesFromHint(), tableShardingStrategy, getTableShardingValuesFromHint());}/*** 是否数据源和表规则都不是Hint策略* @param shardingRule* @param tableRule* @return*/private boolean isRoutingByShardingConditions(final ShardingRule shardingRule, final TableRule tableRule) {return !(shardingRule.getDatabaseShardingStrategyConfiguration(tableRule) instanceof HintShardingStrategyConfiguration|| shardingRule.getTableShardingStrategyConfiguration(tableRule) instanceof HintShardingStrategyConfiguration);}/*** 通过分片条件路由* @param shardingRule* @param tableRule* @param databaseShardingStrategy* @param tableShardingStrategy* @return*/private Collection<DataNode> routeByShardingConditions(final ShardingRule shardingRule, final TableRule tableRule,final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {return shardingConditions.getConditions().isEmpty()? route0(tableRule, databaseShardingStrategy, Collections.emptyList(), tableShardingStrategy, Collections.emptyList()): routeByShardingConditionsWithCondition(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy);}/*** 通过分片条件作为条件路由* @param shardingRule* @param tableRule* @param databaseShardingStrategy* @param tableShardingStrategy* @return*/private Collection<DataNode> routeByShardingConditionsWithCondition(final ShardingRule shardingRule, final TableRule tableRule,final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {Collection<DataNode> result = new LinkedList<>();for (ShardingCondition each : shardingConditions.getConditions()) {Collection<DataNode> dataNodes = route0(tableRule,databaseShardingStrategy, getShardingValuesFromShardingConditions(shardingRule, databaseShardingStrategy.getShardingColumns(), each),tableShardingStrategy, getShardingValuesFromShardingConditions(shardingRule, tableShardingStrategy.getShardingColumns(), each));result.addAll(dataNodes);originalDataNodes.add(dataNodes);}return result;}/*** 混合条件的路由,即包含Hint、又包含其他的规则* @param shardingRule* @param tableRule* @param databaseShardingStrategy* @param tableShardingStrategy* @return*/private Collection<DataNode> routeByMixedConditions(final ShardingRule shardingRule, final TableRule tableRule,final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {return shardingConditions.getConditions().isEmpty()? routeByMixedConditionsWithHint(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy): routeByMixedConditionsWithCondition(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy);}/*** 通过解析的分片条件进行混合条件的路由* @param shardingRule* @param tableRule* @param databaseShardingStrategy* @param tableShardingStrategy* @return*/private Collection<DataNode> routeByMixedConditionsWithCondition(final ShardingRule shardingRule, final TableRule tableRule,final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {Collection<DataNode> result = new LinkedList<>();for (ShardingCondition each : shardingConditions.getConditions()) {Collection<DataNode> dataNodes = route0(tableRule, databaseShardingStrategy,getDatabaseShardingValues(shardingRule, databaseShardingStrategy, each), tableShardingStrategy, getTableShardingValues(shardingRule, tableShardingStrategy, each));result.addAll(dataNodes);originalDataNodes.add(dataNodes);}return result;}/*** 有包含hint的复合条件* @param shardingRule* @param tableRule* @param databaseShardingStrategy* @param tableShardingStrategy* @return*/private Collection<DataNode> routeByMixedConditionsWithHint(final ShardingRule shardingRule, final TableRule tableRule,final ShardingStrategy databaseShardingStrategy, final ShardingStrategy tableShardingStrategy) {// 其中table规则是Hintif (shardingRule.getDatabaseShardingStrategyConfiguration(tableRule) instanceof HintShardingStrategyConfiguration) {return route0(tableRule, databaseShardingStrategy, getDatabaseShardingValuesFromHint(), tableShardingStrategy, Collections.emptyList());}// database规则为Hintreturn route0(tableRule, databaseShardingStrategy, Collections.emptyList(), tableShardingStrategy, getTableShardingValuesFromHint());}/*** 获取数据库的分片条件值* @param shardingRule* @param databaseShardingStrategy* @param shardingCondition* @return*/private List<ShardingConditionValue> getDatabaseShardingValues(final ShardingRule shardingRule, final ShardingStrategy databaseShardingStrategy, final ShardingCondition shardingCondition) {return isGettingShardingValuesFromHint(databaseShardingStrategy)// 如果是Hint类型的策略,从Hint中获取? getDatabaseShardingValuesFromHint()// 如果不是Hint类型的策略,从分片条件对象中获取分片值: getShardingValuesFromShardingConditions(shardingRule, databaseShardingStrategy.getShardingColumns(), shardingCondition);}/*** 获取分片表的值* @param shardingRule* @param tableShardingStrategy* @param shardingCondition* @return*/private List<ShardingConditionValue> getTableShardingValues(final ShardingRule shardingRule, final ShardingStrategy tableShardingStrategy, final ShardingCondition shardingCondition) {return isGettingShardingValuesFromHint(tableShardingStrategy)? getTableShardingValuesFromHint(): getShardingValuesFromShardingConditions(shardingRule, tableShardingStrategy.getShardingColumns(), shardingCondition);}/*** 判断策略是否为Hint类型的策略* @param shardingStrategy* @return*/private boolean isGettingShardingValuesFromHint(final ShardingStrategy shardingStrategy) {return shardingStrategy instanceof HintShardingStrategy;}/*** 从Hint中获取数据库的分片条件值* @return*/private List<ShardingConditionValue> getDatabaseShardingValuesFromHint() {if (isRoutingBySQLHint()) {return getDatabaseShardingValuesFromSQLHint();}return getShardingConditions(HintManager.isDatabaseShardingOnly() ? HintManager.getDatabaseShardingValues() : HintManager.getDatabaseShardingValues(logicTableName));}/*** 从SQL语句中的Hint信息中获取数据库的分片条件值* @return*/private List<ShardingConditionValue> getDatabaseShardingValuesFromSQLHint() {Collection<Comparable<?>> shardingValues = new LinkedList<>();Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();for (String each : tableNames) {// 如果是sql语句中的第一个表if (each.equals(logicTableName) && sqlHintExtractor.containsHintShardingDatabaseValue(each)) {// 创建分片条件值shardingValues.addAll(sqlHintExtractor.getHintShardingDatabaseValue(each));}}return getShardingConditions(shardingValues);}/*** 从Hint中获取分片表的条件值。*/private List<ShardingConditionValue> getTableShardingValuesFromHint() {if (isRoutingBySQLHint()) {return getTableShardingValuesFromSQLHint();}return getShardingConditions(HintManager.getTableShardingValues(logicTableName));}/*** 从SQL的hint中获取分片表的值* @return*/private List<ShardingConditionValue> getTableShardingValuesFromSQLHint() {Collection<Comparable<?>> shardingValues = new LinkedList<>();Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();for (String each : tableNames) {if (each.equals(logicTableName) && sqlHintExtractor.containsHintShardingTableValue(each)) {shardingValues.addAll(sqlHintExtractor.getHintShardingTableValue(each));}}return getShardingConditions(shardingValues);}/*** 创建分片条件值集合。如果传入的集合不为空,则创建ListShardingConditionValue对象,否则为空集合* @param shardingValue* @return*/private List<ShardingConditionValue> getShardingConditions(final Collection<Comparable<?>> shardingValue) {return shardingValue.isEmpty() ? Collections.emptyList() : Collections.singletonList(new ListShardingConditionValue<>("", logicTableName, shardingValue));}/*** 从分片条件对象中获取分片值* @param shardingRule* @param shardingColumns* @param shardingCondition* @return*/private List<ShardingConditionValue> getShardingValuesFromShardingConditions(final ShardingRule shardingRule, final Collection<String> shardingColumns, final ShardingCondition shardingCondition) {List<ShardingConditionValue> result = new ArrayList<>(shardingColumns.size());// 遍历分片条件for (ShardingConditionValue each : shardingCondition.getValues()) {// 查找绑定关联表Optional<BindingTableRule> bindingTableRule = shardingRule.findBindingTableRule(each.getTableName());// (等于逻辑表 || 有关联表 && 关联表是逻辑表) && 属于分片键,则将该分片条件值加入到result中if ((logicTableName.equals(each.getTableName()) || bindingTableRule.isPresent() && bindingTableRule.get().hasLogicTable(logicTableName))&& shardingColumns.contains(each.getColumnName())) {result.add(each);}}return result;}/*** 路由* @param tableRule 表规则* @param databaseShardingStrategy 配置的数据源分片策略* @param databaseShardingValues 数据源分片值* @param tableShardingStrategy 配置的表分片策略* @param tableShardingValues 表的分片值* @return*/private Collection<DataNode> route0(final TableRule tableRule,final ShardingStrategy databaseShardingStrategy, final List<ShardingConditionValue> databaseShardingValues,final ShardingStrategy tableShardingStrategy, final List<ShardingConditionValue> tableShardingValues) {// 数据源路由Collection<String> routedDataSources = routeDataSources(tableRule, databaseShardingStrategy, databaseShardingValues);Collection<DataNode> result = new LinkedList<>();// 遍历数据源for (String each : routedDataSources) {// 表路由result.addAll(routeTables(tableRule, each, tableShardingStrategy, tableShardingValues));}return result;}/*** 数据源路由* @param tableRule* @param databaseShardingStrategy* @param databaseShardingValues* @return*/private Collection<String> routeDataSources(final TableRule tableRule, final ShardingStrategy databaseShardingStrategy, final List<ShardingConditionValue> databaseShardingValues) {// 如果数据没有对应的分片值,即查询的列没有设置数据源分片,则返回实际数据源名称if (databaseShardingValues.isEmpty()) {return tableRule.getActualDataSourceNames();}// 执行分片算法的doSharding(),获取分片的数据源名称集合Collection<String> result = databaseShardingStrategy.doSharding(tableRule.getActualDataSourceNames(), databaseShardingValues, tableRule.getDataSourceDataNode(), props);Preconditions.checkState(!result.isEmpty(), "No database route info");Preconditions.checkState(tableRule.getActualDataSourceNames().containsAll(result),"Some routed data sources do not belong to configured data sources. routed data sources: `%s`, configured data sources: `%s`", result, tableRule.getActualDataSourceNames());return result;}/*** 表路由* @param tableRule 表规则* @param routedDataSource 路由的数据源* @param tableShardingStrategy 表分片策略* @param tableShardingValues 表分片值* @return*/private Collection<DataNode> routeTables(final TableRule tableRule, final String routedDataSource,final ShardingStrategy tableShardingStrategy, final List<ShardingConditionValue> tableShardingValues) {// 获取目标数据源的实际表的集合Collection<String> availableTargetTables = tableRule.getActualTableNames(routedDataSource);Collection<String> routedTables = tableShardingValues.isEmpty()? availableTargetTables// 执行表分片算法的doSharding()方法,获取分片表名: tableShardingStrategy.doSharding(availableTargetTables, tableShardingValues, tableRule.getTableDataNode(), props);Collection<DataNode> result = new LinkedList<>();for (String each : routedTables) {// 创建分片的DataNode对象result.add(new DataNode(routedDataSource, each));}return result;}/*** 根据配置的信息,创建分片策略对象* @param shardingStrategyConfig 分片策略配置,如算法名称、分片键等* @param shardingAlgorithms 分片算法。key为算法的名称,value为对应算法类型的类(如:ClassBasedShardingAlgorithm等)* @param defaultShardingColumn 默认的分片键* @return*/private ShardingStrategy createShardingStrategy(final ShardingStrategyConfiguration shardingStrategyConfig, final Map<String, ShardingAlgorithm> shardingAlgorithms,final String defaultShardingColumn) {return null == shardingStrategyConfig ? new NoneShardingStrategy(): ShardingStrategyFactory.newInstance(shardingStrategyConfig, shardingAlgorithms.get(shardingStrategyConfig.getShardingAlgorithmName()), defaultShardingColumn);}
}

在route()方法中,执行如下:

1)执行getDataNodes(),获取当前SQL的分片数据节点,即真正要执行的数据库及表的映射对象;

1.1)根据配置的分片键的分片策略,创建数据源、表的分片策略对象。如对应分片键配置的策略为standard,则创建StandardShardingStrategy对象。其中的StandardShardingAlgorithm算法对象为算法配置时指定的type所对应的对象。如type配置为CLASS_BASED,则对应的StandardShardingAlgorithm算法对象为ClassBasedShardingAlgorithm。而在ClassBasedShardingAlgorithm中的StandardShardingAlgorithm算法对象才是真正自定义的算法对象;

1.2)根据配置的分片键的分片策略,判断数据源、表的策略条件,分为两种:Hint、非Hint。结合数据源、表,总共有三种场景:数据源、表都为Hint;都不为Hint;其中一种为Hint。针对上面的三种情况,分别判断处理,最后针对Hint和非Hint,获取分片的数据源和表;

1.2.1)如果是Hint的,则从提示中获取指定的数据源或表,创建新的ShardingCondition分片条件集合。逻辑为:

a)先从SQL语句中的注释信息中获取指定的数据源或表;

b)如果没有找到,则从HintManager中获取动态指定的数据源或表;

1.2.2)如果不是Hint,则使用WhereClauseShardingConditionEngine中解析where条件获取的ShardingCondition分片条件集合;

1.3)执行route0()方法,创建分片的数据节点;

1.3.1)执行routeDataSources(),执行数据源的分片算法(如ClassBasedShardingAlgorithm的doSharding()方法,在该方法中,执行自定义的分片算法的doSharding()方法),获取数据源字符串集合;

详见:【源码】Sharding-JDBC源码分析之分片规则生成器DatabaseRuleBuilder实现规则配置到规则对象的生成原理-中的ClassBasedShardingAlgorithm部分

1.3.2)遍历数据源字符串集合,执行routeTables(),执行表的分片算法,获取表字符串集合。同数据源字符串映射,生成DataNode对象。该对象记录分片的真实数据源、表的映射;

2)遍历DataNode集合对象,创建路由映射RouteMapper对象(逻辑表和真实表映射、数据源映射),创建路由单元RouteUnit对象。添加到RouteContext对象中;

3)返回RouteContext对象;

小结

限于篇幅,本篇先分享到这里。以下做一个小结:

1)在ShardingSpherePreparedStatement中真正执行SQL之前,要先创建路由上下文RouteContext对象;

该对象保存了SQL真正执行的数据库、逻辑表及真实表的映射信息;

2)对于非全路由的SQL操作,且没有在SQL的注释中指定数据源,则执行配置的路由器;

路由器包括ShardingSQLRouter(分片路由器)、SingleSQLRouter(单表路由器)、ReadwriteSplittingSQLRouter(读写分离路由器)、DatabaseDiscoverySQLRouter(数据库发现路由器)、ShadowSQLRouter(影子库路由器)。只需进行对应的配置,将自动创建对应的路由器。所有路由器以上面的顺序执行,第一个执行的会创建路由上下文对象,后执行的则合并路由上下文;

3)分片路由器ShardingSQLRouter如果有配置,会是第一个执行的路由器。在该路由器中,主要针对数据库的DML操作进行分片路由,创建路由上下文RouteContext对象;

3.1)DML操作主要分为两类,一种是Insert,另一种是带Where的。对于Insert语句,分片键的值在values部分,处理在InsertClauseShardingConditionEngine;后一种分片键的值在where部分,处理在WhereClauseShardingConditionEngine。通过分片条件引擎,解析分片键及值,创建ShardingCondition集合;

3.2)通过ShardingRouteEngineFactory.newInstance(),获取分片路由引擎。对于DML语句的普通分片规则,返回ShardingStandardRoutingEngine对象;

3.2.1)根据配置的分片键的分片策略,创建数据源、表的分片策略对象。如对应分片键配置的策略为standard,则创建StandardShardingStrategy对象。其中的StandardShardingAlgorithm算法对象为算法配置时指定的type所对应的对象。如type配置为CLASS_BASED,则对应的StandardShardingAlgorithm算法对象为ClassBasedShardingAlgorithm。而在ClassBasedShardingAlgorithm中的StandardShardingAlgorithm算法对象才是真正自定义的算法对象;

3.2.2)如果配置的是Hint策略,则从提示中获取指定的数据源或表(先从SQL的注释中获取,没有从HintManager中获取),创建新的ShardingCondition分片条件集合;

3.2.3)传入ShardingCondition分片条件,执行分片算法,获取实际执行的数据源及表,生成DataNode集合。先执行type对应的分片算法,在算法中执行自定义的分片算法(如果有配置);

3.2.4)遍历DataNode集合,创建路由映射(逻辑表和真实表映射、数据源映射)及路由单元,添加到新创建的路由上下文RouteContext中;

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

相关文章:

【源码】Sharding-JDBC源码分析之SQL中分片键路由ShardingSQLRouter的原理

Sharding-JDBC系列 1、Sharding-JDBC分库分表的基本使用 2、Sharding-JDBC分库分表之SpringBoot分片策略 3、Sharding-JDBC分库分表之SpringBoot主从配置 4、SpringBoot集成Sharding-JDBC-5.3.0分库分表 5、SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表 6、【…...

JavaFX 实现 Loading 效果的组件与案例详解

JavaFX 中的 Loading 组件概述 JavaFX 提供了两个用于显示任务进度的核心组件&#xff1a; ProgressIndicator&#xff1a;以圆形动画的形式展示任务进度&#xff0c;适用于未定义进度的任务。ProgressBar&#xff1a;以水平条的形式展示任务进度&#xff0c;适用于可以量化进…...

Elasticsearch:如何部署文本嵌入模型并将其用于语义搜索

你可以按照这些说明在 Elasticsearch 中部署文本嵌入模型&#xff0c;测试模型并将其添加到推理提取管道。它使你能够生成文本的向量表示并对生成的向量执行向量相似性搜索。示例中使用的模型在 HuggingFace上公开可用。 该示例使用来自 MS MARCO Passage Ranking Task 的公共…...

李继刚:提示词(Prompt)的本质是表达的艺术

看了李继刚在 AI 创新者大会的演讲《提示词的道与术》&#xff0c;收获很大&#xff0c;我分享一下学习笔记。  李继刚&#xff1a;提示词&#xff08;Prompt&#xff09;的本质是表达的艺术 一、提示词的本质是表达 本意、文意和解意的概念&#xff1a; 本意&#xff1a;指…...

10 —— Webpack打包模式

开发模式&#xff1a;development &#xff1b;场景&#xff1a;本地开发 生产模式&#xff1a;production &#xff1b; 场景&#xff1a;打包上线 这两种模式如何设置给webpack&#xff1a; 方式1.webpack.config.js 配置文件设置mode选项 module.exports { mode:produc…...

OpenSSH 安装

OpenSSH windows安装 启用可选功能安装 OpenSSH&#xff08;推荐方法&#xff09; 步骤一&#xff1a;打开 “设置” 应用 点击 “开始” 菜单&#xff0c;选择 “设置” 图标&#xff08;看起来像一个齿轮&#xff09;。 步骤二&#xff1a;进入 “应用” 部分 在设置窗口中&…...

国标GB28181设备管理软件EasyGBS国标GB28181视频平台:RTMP和GB28181两种视频上云协议的区别

在当今信息化高速发展的社会中&#xff0c;视频监控技术已经成为各行各业不可或缺的一部分。无论是城市安全、交通管理&#xff0c;还是企业安全、智能家居&#xff0c;视频监控都发挥着至关重要的作用。然而&#xff0c;随着监控点数量的急剧增加&#xff0c;海量视频数据的存…...

Image fusion meets deep learning: A survey and perspective译文

摘要 图像融合是指从不同的源图像中提取和组合最有意义的信息&#xff0c;旨在生成一个更有信息量和有利于后续应用的单图像。深度学习的发展极大地推动了图像融合的发展&#xff0c;而神经网络强大的特征提取和重建能力使融合结果充满希望。最近&#xff0c;几种最新的深度学…...

多维高斯分布的信息熵和KL散度计算

多维高斯分布是一种特殊的多维随机分布&#xff0c;应用非常广泛&#xff0c;很多现实问题的原始特征分布都可以看作多维高斯分布。本文以数据特征服从多维高斯分布的多分类任务这一理想场景为例&#xff0c;从理论层面分析数据特征和分类问题难度的关系注意&#xff0c;本文分…...

物体网格弹性变形---Unity中实现

在游戏引擎场景中的3D物体是由一定数量的点、面组成的&#xff0c;如下图&#xff1a; 要使这些物体变形就是改变3D物体每个顶点状态。 1.首先在Unity场景中增加一个球体&#xff0c;如下图 3D组件默认拥有MeshFilter、meshRenderer、Collider组件&#xff0c;分别用来获取Mes…...

什么是Sass,有什么特点

Sass 概述 什么是 Sass&#xff1f; Sass&#xff08;Syntactically Awesome Style Sheets&#xff09;是一种 CSS 预处理器&#xff0c;它扩展了 CSS 的功能&#xff0c;使其更加强大和灵活。Sass 允许开发者使用变量、嵌套规则、混合宏、继承等高级特性&#xff0c;从而编写…...

Spring注入Map学习

Spring注入Map学习 在Spring中 在策略模式中, 会经常用到 根据Bean名称获取Bean的实例 有2个方法很好用 1. 使用Autowired注入 2. 使用构造方法注入 但是奇怪的一点是: 日志打印并没有看到结果, 第一行的 Autowired的结果 是个null 那是因为 注入时机 的问题 注入时机&…...

Java 基础知识 (集合框架 + 并发编程 + JVM 原理 + 数据结构与算法)

文章目录 一.集合框架1. 常见集合接口及其特点List 接口Set 接口Map 接口 2. ArrayList 和 LinkedList 的区别和适用场景ArrayListLinkedList 3. HashSet 和 TreeSet 的特点和用法HashSetTreeSet 4. HashMap 和 TreeMap 的实现原理和使用注意事项HashMapTreeMap 5. 集合遍历方式…...

数据脱敏工具:基于 FFmpeg 的视频批量裁剪

在数据处理和隐私保护领域&#xff0c;数据脱敏是一项重要的任务&#xff0c;尤其是在处理包含敏感信息的视频数据时。本文介绍了一种使用 Python 和 FFmpeg 实现的视频批量裁剪工具&#xff0c;该工具可以将视频中的敏感区域裁剪掉&#xff0c;从而实现数据脱敏。通过使用 PyI…...

从零开始:使用 Spring Boot 开发图书管理系统

如何利用是springboot搭建一个简单的图书管理系统&#xff0c;下面让我们一起来看看吧 文章目录 项目结构1. 主类 LibraryApplication.java功能与注意事项&#xff1a; 2. 模型类 Book.java功能与注意事项&#xff1a; 3. 数据仓库接口 BookRepository.java功能与注意事项&…...

深入浅出:大数据架构中的流处理与实时分析

1. 引言 随着数据产生速度的不断加快,传统的批处理架构已经无法满足实时数据处理和快速响应的需求。流处理成为解决这一问题的关键技术之一,广泛应用于金融、互联网、物联网等领域。流处理技术能够处理不断到来的数据流,实时分析和反馈,使得系统能够迅速做出反应,提供实时…...

基于Multisim的汽车尾灯控制电路设计与仿真

1、电路由四个按键控制&#xff0c;分别对应左转、右转、刹车和检查。 2、当左转或右转键按下时,左侧或右侧的 3个汽车尾灯按照左循环或右循环的顺!2/3 点亮&#xff0c;点亮时间为 1秒。 3、当刹车时&#xff0c;所有的尾灯同时闪烁&#xff0c;闪烁时间为1秒。 4、当检查时…...

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理 1. 标题识别elementUI组件爆红 这个原因是&#xff1a; 在官网说明里&#xff0c;才版本2024.1开始&#xff0c;默认启用的 Vue Language Server&#xff0c;但是在 Vue 2 项目…...

【大数据学习 | Spark-Core】详解分区个数

RDD默认带有分区的&#xff0c;那么创建完毕rdd以后他的分区数量是多少&#xff1f; 从hdfs读取文件的方式是最正规的方式&#xff0c;我们通过计算原理可以推出blk的个数和分区数量是一致的&#xff0c;本地化计算。 我们可以发现数据的读取使用的是textInputFormat&#xff…...

(二)Sping Boot学习——Sping Boot注意事项

1.springboot默认是扫描的类是在启动类的当前包或者下级包。 2.运行报错 ERROR&#xff1a;An incompatible version [1.2.33] of the Apache Tomcat Native library is installed, while Tomcat requires version [1.2.34] 网上试了很多方法&#xff0c;直接重新安装更新版…...

深入浅出,快速安装并了解汇编语言

1.什么是汇编语言 了解汇编语言需要先从了解机器语言开始&#xff0c;在计算机发展的初期阶段&#xff0c;机器语言是计算机直接理解和执行的二进制代码语言&#xff0c;其核心特点包括直接执行性、资源高效性、学习难度大以及平台依赖性。它主要由指令码构成&#xff0c;这些…...

LLM的原理理解6-10:6、前馈步骤7、使用向量运算进行前馈网络的推理8、注意力层和前馈层有不同的功能9、语言模型的训练方式10、GPT-3的惊人性能

目录 LLM的原理理解6-10: 6、前馈步骤 7、使用向量运算进行前馈网络的推理 8、注意力层和前馈层有不同的功能 注意力:特征提取 前馈层:数据库 9、语言模型的训练方式 10、GPT-3的惊人性能 一个原因是规模 大模型GPT-1。它使用了768维的词向量,共有12层,总共有1.…...

JavaScript中的箭头函数以及编写优化

箭头函数 1.1.1 箭头函数的概念 箭头函数时ES 6之后增加一种编写函数的方法&#xff0c;并且它比函数的表达式要更加简洁 箭头函数不会绑定this,arguments属性箭头函数不能作为构造函数来使用&#xff08;不能和new一起来使用&#xff0c;会出现错误&#xff09; //1.之前的方…...

Thymeleaf模板引擎生成的html字符串转换成pdf

依赖引入implementation("org.springframework.boot:spring-boot-starter-thymeleaf")implementation("org.xhtmlrenderer:flying-saucer-pdf")将ITemplateEngine注入到spring管理的类中&#xff0c; Context context new Context(); context.setVariable…...

Android 实现双列图片瀑布流式布局

Android 实现双列图片瀑布流式布局 实现双列图片瀑布流布局&#xff0c;关键在于 RecyclerView 的 StaggeredGridLayoutManager 和图片的动态加载。以下是实现步骤&#xff1a; 1. 添加必要依赖 使用 Glide 加载图片。确保在 build.gradle 中添加依赖&#xff1a; implement…...

运维Tips:Docker或K8s集群拉取Harbor私有容器镜像仓库配置指南

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] Docker与Kubernetes集群拉取Harbor私有容器镜像仓库配置 描述:在现在微服务、云原生的环境下,通常我们会在企业中部署Docker和Kubernetes集群,并且会在企业内部搭建Harbor私有镜像仓库以保证开发源码安全,以及加快…...

显示类控件

文章目录 1 QLabel1.1 常用属性1.2 例子1&#xff0c;设置文本 (textFormat)1.3 例子2&#xff0c;设置widget背景图片 (pixmap和scaledContents)1.4 例子3&#xff0c;设置对齐方式 (alignment)1.5 例子4&#xff0c;设置自动换行&#xff0c;缩进和边距1.5.1 设置换行 (wordW…...

AOC显示器915Sw按键失灵维修记

大家好&#xff0c;我是 程序员码递夫 今天给大家分享的是自己维修老古董AOC液晶显示器按键失灵的的过程&#xff0c;实属DIY记录。 1、引子 家里有台老古董的19寸AOC液晶显示器&#xff08;型号915Sw&#xff09;, 一直作为我的副显示器陪伴着左右&#xff0c;显示还正常&a…...

PyQt学习笔记

一.PyQt5的安装 当我们安装好开发环境后&#xff0c;打开pycharm在其设置里面点击按钮自动安装即可。 安装完成后我们会在这里面看到这几个东西说明安装成功了。 二.PyQt5 GUI程序框架 1.一个简单的PyQt5应用程序 首先我们用pycharm创建一个demo.py的文件。 我们创建文件为s…...

LLMops产品介绍

文章目录 字节跳动的扣子优点低代码开发丰富的插件与能力扩展强大的记忆与数据交互能力应用场景广泛 不足模型选择相对受限定制化程度受限输出效果有待提高应用部署范围有限市场认知度和用户基础不足 开悟大模型运营管理系统&#xff08;LLMOPS&#xff09;优点全生命周期管理降…...

【GPTs】Front-end Expert:助力前端开发的智能工具

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | GPTs应用实例 文章目录 &#x1f4af;GPTs指令&#x1f4af;前言&#x1f4af; Front-end Expert主要功能适用场景优点缺点 &#x1f4af;小结 &#x1f4af;GPTs指令 中文翻译&#xff1a; 使用Dalle生成用户…...

一篇保姆式centos/ubuntu安装docker

前言&#xff1a; 本章节分别演示centos虚拟机&#xff0c;ubuntu虚拟机进行安装docker。 上一篇介绍&#xff1a;docker一键部署springboot项目 一&#xff1a;centos 1.卸载旧版本 yum remove docker docker-client docker-client-latest docker-common docker-latest doc…...

人工智能大趋势下软件开发的未来

随着人工智能&#xff08;AI&#xff09;技术的不断演进&#xff0c;软件开发领域正经历着深刻的变革。中国电信推出的星辰大模型软件工厂&#xff0c;作为国内首款破局性AI开发工具&#xff0c;其全自动流水线的特性——自动生成前后端代码、自主测试和纠错等&#xff0c;为软…...

string的模拟实现

string的模拟实现 一.string的模拟实现1.1构造函数和析构函数&#xff0c;以及一些简单函数1.2迭代器1.3增删查改 二.运算符重载三.流插入和流提取 一.string的模拟实现 string本质上是是一种char类型的顺序表&#xff0c;结构上和顺序表相似。 namespace Mystring {class st…...

Qt桌面应用开发 第七天(绘图事件 绘图设备)

目录 1.绘图事件paintEvent 2.高级绘图 3.图片绘制 4.绘图设备 4.1QPixmap 4.2QBitmap 4.3QImage 4.4QPicture 1.绘图事件paintEvent paintEvent——绘图事件 需求&#xff1a;利用QPainter绘制点、线、圆、矩形、文字&#xff1b;设置画笔改为红色&#xff0c;宽度为…...

PDF内容提取,MinerU使用

准备环境 # python 3.10 python3 -m pip install huggingface_hub python3 -m pip install modelscope python3 -m pip install -U magic-pdf[full] --extra-index-url https://wheels.myhloli.com下载需要的模型 import json import osimport requests from huggingface_hub…...

基于lora的llama2二次预训练

基于lora的llama2二次预训练 一、为什么需要对llama2做基于lora的二次预训练? 加入中文训练语料进行llama2的二次预训练&#xff0c;这样模型就可以增加支持中文输出的能力。 二、基于lora的llama2二次预训练的目标是什么&#xff1f; 在保持预训练模型权重不变的情况下&a…...

机器学习之量子机器学习(Quantum Machine Learning, QML)

量子机器学习(Quantum Machine Learning, QML)是一门结合量子计算与机器学习的新兴交叉领域。它利用量子计算的优势(如并行计算、量子叠加和量子纠缠)来解决传统机器学习中难以处理的问题,或提升算法效率和性能。 QML 的核心要素 量子计算的特性: 量子叠加:允许量子比特…...

【2024 Optimal Control 16-745】【Lecture 3 + Lecture4】minimization.ipynb功能分析

主要功能-最小化问题 目标函数分析: 定义函数 f ( x ) f(x) f(x) 及其一阶、二阶导数。使用绘图工具可视化函数的形状。 实现数值优化: 使用牛顿法寻找函数的极值点&#xff0c;结合一阶和二阶导数加速收敛。使用正则化牛顿法解决二阶导数矩阵可能不正定的问题。 可视化过程…...

一种新的电机冷却方式——热管冷却

在现代工业设备中&#xff0c;电机作为一种核心动力装置&#xff0c;广泛应用于各个领域。例如&#xff0c;家用电器、自动化生产线、交通工具等都离不开电机的运作。然而&#xff0c;随着电机功率的不断提升和负载的增加&#xff0c;电机在运行过程中产生的热量也随之增多&…...

虚拟机上搭建达梦DSC简略步骤

vmware 17 centos 7.6 达梦 dm8_20240920_x86_rh7_64.iso cd /d C:\Program Files (x86)\VMware\VMware Workstation\.\vmware-vdiskmanager.exe -c -s 100MB -a lsilogic -t 2 "F:\vm\dmdsc\sharedisk\share-dcr.vmdk" .\vmware-vdiskmanager.exe -c -s 100MB -a l…...

C++ 矩阵旋转

【问题描述】 编写一个程序&#xff0c;读入一个矩阵&#xff0c;输出该矩阵以第一行第一列数字为中心&#xff0c;顺时针旋转90度后的新矩阵&#xff0c;例如&#xff1a; 输入的矩阵为: 1 2 3 4 5 6 顺时针旋转90度后输出的矩阵为&#xff1a; 4 1 5 2 6 3 【输入…...

mongodb基础操作

创建数据库 use admin授权 db.auth("admin","123456")创建用户 db.createUser({ user: "xxx", pwd: "xxxxxx", roles: [ { role: "readWrite", db: "iot" } ] })查询数据库大小 show dbs;查询结果数量 db.mo…...

以思维链为线索推理隐含情感

❀ 以思维链为线索推理隐含情感 简介摘要引言THORTHOR核心代码实验结果代码运行总结 简介 本文主要对2023ACL论文《Reasoning Implicit Sentiment with Chain-of-Thought Prompting》主要内容进行介绍。 摘要 尽管情绪分析任务常依据文本中的直接意见表达来判定目标的情绪倾向…...

(笔记,自己可见_1)简单了解ZYNQ

1、zynq首先是一个片上操作系统&#xff08;Soc&#xff09;&#xff0c;结合了arm&#xff08;PS&#xff09;和fpga&#xff08;PL&#xff09;两部分组成 Zynq系统主要由两部分组成&#xff1a;PS&#xff08;Processing System&#xff09;和PL&#xff08;Programmable L…...

部署自动清理任务解决ORA-00257: archiver error. Connect internal only, until freed

使用oracle数据库的时候&#xff0c;我们一般都会开启归档&#xff0c;确保数据库的日志连续和和数据安全。但随着数据库的运行&#xff0c;归档文件会越来越多&#xff0c;最终撑满磁盘空间&#xff0c;数据库无法继续归档&#xff0c;出现“ORA-00257: archiver error. Conne…...

scau编译原理综合性实验

一、题目要求 题目&#xff1a; 选择部分C语言的语法成分&#xff0c;设计其词法分析程序、语法语义分析程序。 要求&#xff1a; 设计并实现一个一遍扫描的词法语法语义分析程序&#xff0c;将部分C语言的语法成分&#xff08;包含赋值语句、if语句、while循环语句&#xf…...

[Docker-显示所有容器IP] 显示docker-compose.yml中所有容器IP的方法

本文由Markdown语法编辑器编辑完成。 1. 需求背景: 最近在启动一个服务时&#xff0c;突然发现它的一个接口&#xff0c;被另一个服务ip频繁的请求。 按理说&#xff0c;之前设置的是&#xff0c;每隔1分钟请求一次接口。但从日志来看&#xff0c;则是1秒钟请求一次&#xff…...

PICO VR串流调试Unity程序

在平时写Unity的VR程序的时候&#xff0c;需要调试自己写的代码&#xff0c;但是有的时候会发现场景过于复杂&#xff0c;不是HMD一体机能运行的&#xff0c;或者为了能够更方便的调试&#xff0c;不需要每次都将程序部署到眼睛里&#xff0c;这样非常浪费时间&#xff0c;对于…...

ESP-KeyBoard:基于 ESP32-S3 的三模客制化机械键盘

概述 在这个充满挑战与机遇的数字化时代&#xff0c;键盘已经成为我们日常学习、工作、娱乐生活必不可少的设备。而在众多键盘中&#xff0c;机械键盘&#xff0c;以其独特的触感、清脆的敲击音和经久耐用的特性&#xff0c;已经成为众多游戏玩家和电子工程师的首选。本文将为…...