Инвентаризация Sharding-JDBC: подбаза данных и подтаблица

Java
Инвентаризация Sharding-JDBC: подбаза данных и подтаблица

Общая документация:Каталог статей
Github : github.com/black-ant

Введение

Я не планировал смотреть эту часть исходного кода, причина этого в том, чтоЯ раньше пользовался версией 3.0, в этот раз увидел 5.0 и хотел попробовать, но не получилось, официальная документация не сильна, я просто прочитал исходники и нашел проблему.....

2. Исходная точка вещей

Вызвано использованиемshardingsphere-jdbc-core-spring-boot-starterЗависимость, хочу выполнить всю настройку напрямую через конфигурационный файл, но во всем процессе много проблем.

К счастью, я написал конфигурацию Bean раньше, просто чтобы сравнить проблемы всего процесса.

2.1 Метод настройки Java Bean

Здесь весь процесс настройки Java Bean вставлен для сравнения.Оба используют JPA в качестве фреймворка постоянства.

Конфигурация Maven

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core</artifactId>
    <version>5.0.0-alpha</version>
</dependency>

Конфигурация конфигурации

@Configuration
public class DatabaseConfig {

    /**
     * 方式一 : 通过 Bean 配置
     */
    @Bean
    public DataSource dataSource() {
        // 配置真实数据源
        Map<String, DataSource> dataSourceMap = new HashMap<>();

        // 配置第 1 个数据源
        BasicDataSource dataSource1 = new BasicDataSource();
        dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource1.setUrl("jdbc:mysql://127.0.0.1:3306/database0?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC");
        dataSource1.setUsername("root");
        dataSource1.setPassword("123456");
        dataSourceMap.put("ds0", dataSource1);

        // 配置第 2 个数据源
        BasicDataSource dataSource2 = new BasicDataSource();
        dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource2.setUrl("jdbc:mysql://127.0.0.1:3306/database1?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC");
        dataSource2.setUsername("root");
        dataSource2.setPassword("123456");
        dataSourceMap.put("ds1", dataSource2);

        // 配置 t_order 表规则
        ShardingTableRuleConfiguration orderTableRuleConfig = new ShardingTableRuleConfiguration("t_blog", "ds${0..1}.t_blog_${0..1}");

        // 配置主键生成策略
        KeyGenerateStrategyConfiguration configuration = new KeyGenerateStrategyConfiguration("id", null);
        orderTableRuleConfig.setKeyGenerateStrategy(configuration);

        // 配置分库策略
        orderTableRuleConfig.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("column_id", "dbShardingAlgorithm"));

        // 配置分表策略
        orderTableRuleConfig.setTableShardingStrategy(new StandardShardingStrategyConfiguration("title_id", "tableShardingAlgorithm"));

        // 配置分片规则
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTables().add(orderTableRuleConfig);

        // 配置分库算法
        Properties dbShardingAlgorithmrProps = new Properties();
        dbShardingAlgorithmrProps.setProperty("algorithm-expression", "ds${column_id % 2}");
        shardingRuleConfig.getShardingAlgorithms().put("dbShardingAlgorithm", new ShardingSphereAlgorithmConfiguration("INLINE", dbShardingAlgorithmrProps));

        // 配置分表算法
        Properties tableShardingAlgorithmrProps = new Properties();
        tableShardingAlgorithmrProps.setProperty("algorithm-expression", "t_blog_${title_id % 2}");
        shardingRuleConfig.getShardingAlgorithms().put("tableShardingAlgorithm", new ShardingSphereAlgorithmConfiguration("INLINE", tableShardingAlgorithmrProps));

        DataSource dataSource = null;
        try {
            dataSource = ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, Collections.singleton(shardingRuleConfig), new Properties());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //logger.info("datasource : {}", dataSource);
        return dataSource;
    }
}

класс сущности

@Entity
@Table(name = "t_blog")
public class BlogEntity {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "title")
    private String title;

    @Column(name = "title_id")
    private Integer titleId;

    @Column(name = "author")
    private String author;

    @Column(name = "date")
    private Date date;

    @Column(name = "column_id")
    private Integer columnId;
    
    //.......................
}

3. Способ настройки свойств

Дабы не вводить в заблуждение, файл конфигурации выложен в конце, а начинаем с исключения

java.util.NoSuchElementException: No value bound

Это первое исключение, которое возникает. Глядя на стек исключений, есть несколько важных советов:

Caused by: java.lang.reflect.InvocationTargetException: null
	at org.apache.shardingsphere.spring.boot.util.PropertyUtil.v2(PropertyUtil.java:111) ~[shardingsphere-jdbc-spring-boot-starter-infra-5.0.0-alpha.jar:5.0.0-alpha]
	at org.apache.shardingsphere.spring.boot.util.PropertyUtil.handle(PropertyUtil.java:75) ~[shardingsphere-jdbc-spring-boot-starter-infra-5.0.0-alpha.jar:5.0.0-alpha]
	at org.apache.shardingsphere.spring.boot.datasource.DataSourceMapSetter.getDataSourceMap(DataSourceMapSetter.java:66) ~[shardingsphere-jdbc-spring-boot-starter-infra-5.0.0-alpha.jar:5.0.0-alpha]

// 可以看到 , 出问题的地方为 org.apache.shardingsphere.spring.boot.util.PropertyUtil.v2

// 往上2步 , 可以跟踪到节点 : getDataSourceMap
// 这里就是我们第一个要看的地方 : 多数据源的加载


// 先看下异常的原因 , 再看看整体逻辑
public static Map<String, DataSource> getDataSourceMap(final Environment environment) {
    Map<String, DataSource> result = new LinkedHashMap<>();
    Map<String, Object> dataSourceCommonProps = PropertyUtil.handle(environment, COMMON_PREFIX, Map.class);

//...

}


// 基本上可以按出来 , 这里缺少 COMMON_PREFIX 打头的配置项 , 查了相关资料 ,大概是这2句 
spring.shardingsphere.datasource.common.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.common.driver-class-name=com.mysql.jdbc.Driver

// 问题解决 , 看看整体逻辑


3.1 Несколько источников данных

3.1.1 Загрузка нескольких источников данных

// 核心的配置加载来自于 org.apache.shardingsphere.spring.boot 包下 , 配置了如下
C10- SpringBootConfiguration 
    F01- SpringBootPropertiesConfiguration : 该类种只有一个 Properties 属性
    F02- Map<String, DataSource> dataSourceMap : 维护了一个 DataSource 的列表
    M10_01- shardingSphereDataSource
        - ShardingSphereDataSourceFactory.createDataSource : 传入 Map 集合创建 DataSource -> M11_01
    M10_02- ShardingTransactionTypeScanner : 事务相关
        
C11- ShardingSphereDataSourceFactory : Datasource 的工厂类
	M11_01- createDataSource(Map<String, DataSource>,Collection<RuleConfiguration>, Properties)
            ?- 创建一个 DataSource , 可以看到 , 这里传入的是一个 DataSource 的集合 , 盲猜原理是创建一个虚拟的DataSource
            ?- Map<String, DataSource> -> PS_M11_01_1
            - new ShardingSphereDataSource(dataSourceMap, configurations, props) -> C12MC
            
// M11_01 代码
public static DataSource createDataSource(final DataSource dataSource, final Collection<RuleConfiguration> configurations, final Properties props) throws SQLException {
    Map<String, DataSource> dataSourceMap = new HashMap<>(1, 1);
    dataSourceMap.put(DefaultSchema.LOGIC_NAME, dataSource);
    return createDataSource(dataSourceMap, configurations, props);
}
            
            
// 由 M11_01 中构建相关对象
C12- ShardingSphereDataSource
    MC- ShardingSphereDataSource
        - 生成一个 DatabaseType -> M12_01
        - 构建一个 SchemaContextsBuilder
        - 构建一个 TransactionContexts
    M12_01- createDatabaseType(final Map<String, DataSource> dataSourceMap)
    	FOR- 对 dataSourceMap 循环 , 分别调用 createDatabaseType -> M12_02
    	- 返回的是最后一个 DataSource 的 DatabaseType 
            ?- 这里的 FOR 循环目的是什么 ? 既然返回的一定是最后一个 , 那循环那么多干嘛
    M12_02- createDatabaseType(final DataSource dataSource)
    	?- 注意 , 这里是2个参数不同的方法
            - dataSource.getConnection() : 获取 Connect 
            - 生成 DatabaseType
    
// M12_02伪代码  : 通过 DatabaseTypeRegistry 获取 DatabaseType , 此处拿到的是 MySQLDatabaseType 
private DatabaseType createDatabaseType(final DataSource dataSource) throws SQLException {
    if (dataSource instanceof ShardingSphereDataSource) {
        return ((ShardingSphereDataSource) dataSource).schemaContexts.getDatabaseType();
    }
    try (Connection connection = dataSource.getConnection()) {
        return DatabaseTypeRegistry.getDatabaseTypeByURL(connection.getMetaData().getURL());
    }
}
    


PS_M11_01_1: входящий ресурс зависит от свойства spring.shardingsphere.datasource.names.

image-20210427141008081.png

Как видите, хотя в моей конфигурации настроено 3 источника данных, конечное использование зависит от свойства spring.shardingsphere.datasource.names.


// 此处为 dataSourceMap , 用于扫描配置中的数据源 ,起点逻辑为 :

// PS : 该方法为 EnvironmentAware 接口的实现方法 , 会在ApplicationContextAwareProcessor 中默认调用
public final void setEnvironment(final Environment environment) {
    dataSourceMap.putAll(DataSourceMapSetter.getDataSourceMap(environment));
}


// 扫描具体的 DataSource
C- DataSourceMapSetter
    F- private static final String PREFIX = "spring.shardingsphere.datasource.";
    F- private static final String COMMON_PREFIX = "spring.shardingsphere.datasource.common.";
    M1- getDataSourceMap
        - 获取 Common 属性 : spring.shardingsphere.datasource.common.
        - 获取 Srouce 名称集合 -> M2
        - 依次生成 DataSource 放入集合 -> M3
    M2- getDataSourceNames : 获取 datasource Name , 名称为拼接出来的
        - 优先获取 spring.shardingsphere.datasource.name
        - 没有则获取 spring.shardingsphere.datasource.names
    M3- getDataSource 
        - Map<String, Object> dataSourceProps = mergedDataSourceProps(...) : 生成属性
        - Preconditions.checkState(...) : 校验参数是否合法
        - DataSourceUtil.getDataSource(...) : 创建 DataSource
        - 后面是一个语法糖 , 用于注入属性 -> PS_M3_001
    
// PS_M3_001 : 最终执行语句就是 HikariDataSourcePropertiesSetter # propertiesSet
// 会获取 Environment 中 spring.shardingsphere.datasource.ds1.data-source-properties 前缀 , 设置相关属性
DataSourcePropertiesSetterHolder.getDataSourcePropertiesSetterByType(dataSourceProps.get(DATA_SOURCE_TYPE).toString()).ifPresent(propsSetter -> propsSetter.propertiesSet(environment, prefix, dataSourceName, result));

3.1.2 Сводка по нескольким источникам данных

Отправная точка : SpringBootConfiguration
Ядро обработки: ShardingSphereDataSourceFactory#createDataSource
Строительная единица: ShardingSphereDataSource
Класс сканирования: DataSourceMapSetter

Краткое содержание одной фразы:

  • SpringBootConfiguration реализуетEnvironmentAwareМетод setEnvironment в SpringBootConfiguration будет вызываться по умолчанию при загрузке контейнера.
  • Метод setEnvironment просканирует конфигурацию источника данных в файле конфигурации и поместит ее в коллекцию dataSourceMap.
  • SpringBootConfiguration использует эту карту при использовании shardingSphereDataSource для загрузки нескольких источников данных.
  • Метод shardingSphereDataSource вызывает ShardingSphereDataSourceFactory для создания источника данных.
  • ShardingSphereDataSourceFactory в конечном итоге создаст ShardingSphereDataSource, который идентифицирует источник данных.

3.2 Конфигурация стратегии подбазы данных и подтаблицы

После прогона конфигурации возникает еще одна проблема:

java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).

Приведенное выше исключение генерируется во время выполнения.Хотя это проблема SQL, моя интуиция подсказывает мне, что это все еще отклонение от конфигурации.

Итак, выполните следующие действия, чтобы проверить:

// Step 1 : PreparedStatement  # checkBounds
// 异常栈第一步就是这里 , 发现校验出现问题 , 抛出了异常
if ((paramIndex < 1)) {
    throw SQLError.createSQLException(........);
} else if (paramIndex > this.parameterCount) {
    throw SQLError.createSQLException(.......);    
}........
    
    
// Step 2 : 排查 PreparedStatement 初始化方法
C- PreparedStatement    
    M-initializeFromParseInfo()
    	- 观察 staticSqlStrings 发现 , 参数是错误的 , 只有一个数组
insert into org.apache.shardingsphere.sharding.rewrite.token.pojo.TableToken@3df8c40 (author, column_id, date, title, title_id, id) values org.apache.shardingsphere.sharding.rewrite.token.pojo.ShardingInsertValuesToken@c1b5afe
// 此处发现这个值也是错误的 , 猜测应该是 分表时 , table 处理出现异常
    
    
// Step 3 : 排查分表的逻辑
C79- ShardingRouteEngine
    M79_05- route0
        - routeDataSources 获取策略判断的 DataSource 节点
        - routeTables 获取判断的 table 表

// StandardShardingStrategy # doSharding
target = shardingAlgorithm.doSharding(availableTargetNames, new PreciseShardingValue(shardingValue.getTableName(), shardingValue.getColumnName(), each));

// 这里 debug 发现 shardingValue.getTableName() 名称不对 -------> dt_blog_1 , 应该是t_blog_1
// 我的天.....这一看就是配置问题了 , 检查一下
spring.shardingsphere.rules.sharding.sharding-algorithms.db-algorithm.props.algorithm-expression=dt_blog_$->{title_id % 2}

// 改为 
spring.shardingsphere.rules.sharding.sharding-algorithms.db-algorithm.props.algorithm-expression=t_blog_$->{title_id % 2}

// 一个通过源码排查异常的流程旧结束了 , 重新

На самом деле это проблема конфигурации, но информация об исключении, возвращаемая Sharding, не видна.

Суммировать

В основном обратите внимание наC79- ShardingRouteEngine / M79_05- route0метод, в модифицированном методе есть два основных метода, и в этом методе основное суждение о подбиблиотеке и подтаблице

Запишите путь загрузки стратегии здесь:

Хотя это свойства, он все же использует класс загрузки yml, который не конфликтует

Что такое конкретная конфигурация, вы, вероятно, можете узнать ее по классу YamlShardingRuleConfiguration.


// 配置映射
C- YamlShardingStrategyConfiguration
	?- 数据配置在上一步被配置到当前的 Configuration , 可以通过该类中的属性进行直接配置 

// Rule 规则
C- ShardingRuleSpringBootConfiguration
     
C- ShardingRuleAlgorithmProviderConfigurationYamlSwapper

C- ShardingTableRuleConfigurationYamlSwapper
    
// algorithm-expression 的注入位置
C- ShardingRule
    M- ShardingRule(final AlgorithmProvidedShardingRuleConfiguration config, final Collection<String> dataSourceNames) 

3.3 Логика подбазы данных и подтаблицы

Очень хорошо, наконец-то проект запустился, но не реализована функция подбазы и подтаблицы, при запуске создаются все четыре таблицы.

Отладка обнаружила, что в результате ShardingSphere PreparedStatement было возвращено четыре данных.

PS:M74_02_01

sharding-jdbc-executionContext.jpg

Итак, следуйте следующему процессу, чтобы пройти процесс подтаблицы подбазы данных:

Как видите, первый входной класс — это ShardingSpherePreparedStatement.

Step 1 : ShardingSpherePreparedStatement

Этот класс является классом входа, и связанные операции можно искать в этом классе:

  • Основной:StatementExecuteUnit, полученный в M74_01, — это окончательный SQL, который будет выполняться, который уже содержит библиотеки, которые необходимо запустить (см. рисунок выше), поэтому при выполнении createExecutionContext соответствующие данные были сгенерированы.
  • Ядро два:PreparedStatementExecutor.executeUpdate в M74_01 инициирует выполнение
C74- ShardingSpherePreparedStatement
    M74_01- executeUpdate() : 执行插入操作 
        ?- 这个里面有3个核心操作 , 获取需要执行的 statement + update 执行语句
        - createExecutionContext 创建一个 ExecutionContext  -> M74_03
            ?- 核心逻辑 , 生成需要执行的对象 ExecuteUnit
        - getInputGroups 获取一个 StatementExecuteUnit 集合 -> M74_02
        - preparedStatementExecutor.executeUpdate 执行当前语句
    M74_02- getInputGroups()
        ?- 核心逻辑就是通过相关的 rule 规则生成对应的执行语句
        - 构建一个 PreparedStatementExecuteGroupEngine
        - 调用 PreparedStatementExecuteGroupEngine generate 方法获取数据 
            ?- 参数一 : executionContext.getRouteContext() 
            ?- 参数二 : executionContext.getExecutionUnits() -> PS:M74_02_01
    M74_03- createExecutionContext()
        - kernelProcessor.generateExecutionContext 生成 ExecutionContext -> M75_01
        - findGeneratedKey 创建主键
                
    
// M74_02 代码
private Collection<InputGroup<StatementExecuteUnit>> getInputGroups() throws SQLException {
    // 最大连接数
    int maxConnectionsSizePerQuery = schemaContexts.getProps().<Integer>getValue(ConfigurationPropertyKey.MAX_CONNECTIONS_SIZE_PER_QUERY);
    // 
    return new PreparedStatementExecuteGroupEngine(maxConnectionsSizePerQuery, connection, statementOption,
                schemaContexts.getDefaultSchema().getRules()).generate(executionContext.getRouteContext(), executionContext.getExecutionUnits());
}

Зная, что источник находится в M74_01, продолжайте смотреть вниз -> M75_01

Шаг 2: основная логика обработки правила

// 该类中只有一个方法
C75- KernelProcessor
    M75_01- generateExecutionContext
        1- 获取 ShardingSphereRule 集合
        2- 创建一个 SQLRouteEngine
        3- 获取一个 SQLStatementContext  : 这里可以映射为一个数据库操作
        4- 获取 RouteContext : 这个对象决定将会执行几个数据库/数据表 -> M76_01
        
// M75_01  
public ExecutionContext generateExecutionContext(final LogicSQL logicSQL, final ShardingSphereSchema schema, final ConfigurationProperties props) {
        // PS:M75_01_01 rule 规则对象
        Collection<ShardingSphereRule> rules = schema.getRules();
        SQLRouteEngine sqlRouteEngine = new SQLRouteEngine(rules, props);
        SQLStatementContext<?> sqlStatementContext = logicSQL.getSqlStatementContext();
        
        // 核心语句 : 获取 RouteContext : 这个对象决定将会执行几个数据库/数据表 -> M76_01
        RouteContext routeContext = sqlRouteEngine.route(logicSQL, schema);
        SQLRewriteEntry rewriteEntry = new SQLRewriteEntry(schema.getMetaData().getSchemaMetaData().getConfiguredSchemaMetaData(), props, rules);
        SQLRewriteResult rewriteResult = rewriteEntry.rewrite(logicSQL.getSql(), logicSQL.getParameters(), sqlStatementContext, routeContext);
        Collection<ExecutionUnit> executionUnits = ExecutionContextBuilder.build(schema.getMetaData(), rewriteResult, sqlStatementContext);
        return new ExecutionContext(sqlStatementContext, executionUnits, routeContext);
}


PS: M75_01_01 Структура правил

Видно, что в нем уже есть несколько источников данных, правила сегментирования.

image.png

Остальное просто, просто найдите то место, с которым разобрались раньше

Шаг 3: Отладка шаг за шагом

C76- SQLRouteEngine
    M76_01- route : 
        - 创建一个 SQLRouteExecutor 
             ?- 参数 : new PartialSQLRouteExecutor(rules, props) , 这里就将所有的 Rule 注入到体系中了
         - executor.route 调用执行器执行 rule  -> M77_01
                
                
C77- PartialSQLRouteExecutor
    M77_01- route : 终于找到了 , 这里通过 Rule 规则生成相关的 SQLRouter
        - entry.getValue().createRouteContext(logicSQL, schema, entry.getKey(), props) : 核心语句 -> M78_01
            
C78- ShardingSQLRouter
    M78_01- createRouteContext
        - ShardingRouteEngineFactory 构建一个 RouteEngine 并且调用对应 route 方法 -> M79_01
        
C79- ShardingRouteEngine
    M79_01- route(RouteContext routeContext, ShardingRule shardingRule)
        - getDataNodes 获取 Collection<DataNode> : -> M79_03
            ?- 此处的 Node 会用于下面生成 RouteUnit -> PS:M79_01_02
         FOR- 循环获取的 Nodes , 创建 RouteUnit
    M79_02- getDataNodes
        - createShardingStrategy 创建策略
    M79_03- routeByShardingConditions  
        ?- 这里会通过 Condition 不同分别调用2个方法
         - route0 -> M79_05
         - routeByShardingConditionsWithCondition -> M79_04
    M79_04- routeByShardingConditionsWithCondition : 核心逻辑1
        For- 循环所有的 Condition , 获取策略和 ShardingValues 值 , 调用 route0 
    M79_05- route0
        - routeDataSources 获取策略判断的 DataSource 节点
        - routeTables 获取判断的 table 表
     M79_06- routeTables 
        - 这里就会调用对应的 Strategy 策略类
        
// PS : 如果这里发现 TableRule 存在问题 , 可以查看方法 是否存在问题
private Collection<DataNode> getDataNodes(final ShardingRule shardingRule, final TableRule tableRule) {
    ShardingStrategy databaseShardingStrategy = createShardingStrategy(shardingRule.getDatabaseShardingStrategyConfiguration(tableRule), shardingRule.getShardingAlgorithms());
    ShardingStrategy tableShardingStrategy = createShardingStrategy(shardingRule.getTableShardingStrategyConfiguration(tableRule), shardingRule.getShardingAlgorithms());
    if (isRoutingByHint(shardingRule, tableRule)) {
        return routeByHint(tableRule, databaseShardingStrategy, tableShardingStrategy);
    }
    if (isRoutingByShardingConditions(shardingRule, tableRule)) {
        return routeByShardingConditions(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy);
    }
    return routeByMixedConditions(shardingRule, tableRule, databaseShardingStrategy, tableShardingStrategy);
}


// M79_03 源代码
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);
}


C80- StandardShardingStrategy
    M80_01- doSharding
  

Я не буду вдаваться в подробности здесь, после пошаговой отладки я обнаружил, чтоM79_04- routeByShardingConditionsWithConditionВ конфигурационном файле отсутствуют сопутствующие стратегии, да и конфигурационный файл неверный.После заполнения все в норме

окончательный файл конфигурации

server.port=8085
##Jpa配置
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
# 开启配置
spring.shardingsphere.enabled=true
# 配置真实数据源 ds0,ds1,ds2
spring.shardingsphere.datasource.names=ds0,ds1
spring.shardingsphere.datasource.common.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.common.driver-class-name=com.mysql.jdbc.Driver
# 配置第 1 个数据源
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://127.0.0.1:3306/database0?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
# 配置第 2 个数据源
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://127.0.0.1:3306/database1?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456
# 配置表策略 -- ShardingTableRuleConfiguration
spring.shardingsphere.rules.sharding.tables.t_blog.actual-data-nodes=ds$->{0..1}.t_blog_$->{0..1}
# 配置主键策略 -- KeyGenerateStrategyConfiguration
spring.shardingsphere.rules.sharding.tables.t_blog.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.t_blog.key-generate-strategy.key-generator-name=snowflake
# 配置分表策略 StandardShardingStrategyConfiguration
spring.shardingsphere.rules.sharding.tables.t_blog.binding-tables=t_blog
spring.shardingsphere.rules.sharding.tables.t_blog.table-strategy.standard.sharding-column=title_id
spring.shardingsphere.rules.sharding.tables.t_blog.table-strategy.standard.sharding-algorithm-name=db-algorithm
# 配置分库策略  StandardShardingStrategyConfiguration
spring.shardingsphere.rules.sharding.tables.t_blog.database-strategy.standard.sharding-column=column_id
spring.shardingsphere.rules.sharding.tables.t_blog.database-strategy.standard.sharding-algorithm-name=table-algorithm
# ================================
# =====================配置默认策略
# 默认插入类型
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-column=id
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-name=database_inline
# 指定 algorithms
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.props.algorithm-expression=ds$->{id % 2}
# 默认算法
spring.shardingsphere.rules.sharding.key-generators.snowflake.type=SNOWFLAKE
spring.shardingsphere.rules.sharding.key-generators.snowflake.props.worker-id=123
# 切分策略
spring.shardingsphere.rules.sharding.sharding-algorithms.db-algorithm.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.db-algorithm.props.algorithm-expression=t_blog_$->{title_id % 2}
spring.shardingsphere.rules.sharding.sharding-algorithms.table-algorithm.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.table-algorithm.props.algorithm-expression=ds$->{column_id % 2}


# !!!!! 对应表 t_blog_0 , t_blog_1 , 已经上面2个库

Суммировать

Самое хлопотное в Sharding-JDBC анализе это выражение ломбока.Отлаживать его хлопотно,и приходится настраивать по одному.Подумав об этой привычке раньше,мне повезло больше.

Во всем процессе в основном есть 3 узла:

  • SpringBootConfiguration
  • ShardingRouteEngine
  • StandardShardingStrategy

Середина головы и хвоста все здесь.Используя эти три узла для отладки, в основном проблема выйдет.

Необходимо понимать следующее: sharding-jdbc будет генерировать несколько ExecuteUnits после выполнения стратегии, каждый ExecuteUnit является объектом обработки базы данных и будет выполняться в соответствующей базе данных/таблице данных.

Давайте взглянем на основную логику его распределенной транзакции и разделения чтения-записи позже, здесь так много