ShardingSphere-JDBC 5.1 动态更新actual-data-nodes

前言

项目中根据年份进行分表(主要存放着日志类数据),每年会生成新的表,所以actual-data-nodes属性需要在不重新启动的前提下动态更新,网上找了好多相关的修改办法,大多都是4.x版本的,最后在官方Github的Issues中找到了相应的解答
链接:https://github.com/apache/shardingsphere/issues/16725
上述链接的答疑中,已经提供了相应的解决办法,我在尝试的过程中想到了一种更简便的办法(其实就是把文中的两种方式结合了一下),下面细说

actual-data-nodes

回答中提到actual-data-nodes除了使用Groovy表达式(如下)的方式以外

actual-data-nodes: ds.table_name_$->{2023...2024}

还可以使用静态方法的形式配置(我在官方文档中没看到这种形式,可能是没找到),如下

actual-data-nodes: ds.table_name_$->{com.demo.util.LocalShardingDatabasesAndTablesUtils.getActualDataNodes()}
public class LocalShardingDatabasesAndTablesUtils {

    public static int offset = 1;
    
    public static List<String> getActualDataNodes() {
        int startYear = 2023;
        int endYear = LocalDate.now().getYear() + offset;
        return LongStream.range(startYear, endYear)
                .mapToObj(Long::toString)
                .collect(Collectors.toList());
    }
}

上述代码片段只是一种配置actual-data-nodes的方式,并不能起到动态更新的作用,只会在项目初始化时执行一次

动态更新

那么如何动态更新呢,这里需要获取到ShardingSphereDataSource数据源(我这里是Spring直接注入进来的),代码如下

@Component
public class InitActualDataNodesAO {
    @Resource
    private ShardingSphereDataSource shardingSphereDataSource;
    // ShardingSphere中默认值是logic_db,可以通过shardingsphere.schema.name在spring的配置文件中修改
    private final String schemaName = "logic_db";

    public void testSharding() {
        this.reloadShardRuleActualDataNodes(shardingSphereDataSource, schemaNameForTOrder);
    }

    private void reloadShardRuleActualDataNodes(ShardingSphereDataSource dataSource, String schemaName) {
        // Context manager.
        org.apache.shardingsphere.mode.manager.ContextManager contextManager = dataSource.getContextManager();

        // Rule configuration.
        Collection<RuleConfiguration> ruleConfigList = dataSource.getContextManager()
                .getMetaDataContexts()
                .getMetaData(schemaName)
                .getRuleMetaData()
                .getConfigurations();
        // update context
        contextManager.alterRuleConfiguration(schemaName, ruleConfigList);
    }
}

原文中的方式是通过代码生成新的Groovy表达式,然后创建新的分片规则,获取并将旧规则中除actual-data-nodes以外的所有配置复制到新的规则中,之后执行contextManager.alterRuleConfiguration(schemaName, newRuleConfigList)从而达到更新的目的。
而在我的代码示例中,因为actual-data-nodes配置的方式是静态方法,方法内编写了根据时间动态生成对应的分片集合,只需要在合适的时机调用contextManager.alterRuleConfiguration(schemaName, ruleConfigList)方法,ShardingSphere-JDBC就会重新调用我们提供的静态方法,从而达到动态更新actual-data-nodes的目的

总结

官方的问答中已经提供了一种更新方法,我这里只是取巧,简化了一些步骤,具体使用哪种形式,还需大家自行考虑
另外具体更新的时机需要结合项目中的业务调整,比如我示例中的业务是每年生成一张新的表,也就是每年年初或上年年末执行即可,写在定时任务中即可,而且由于actual-data-nodes是根据代码生成的,在项目重启后,也会根据我们自己编写的逻辑生成保持最新状态,不需要手动修改,至于具体的生成逻辑,根据项目业务实际情况调整即可。
希望能帮到大家,少走弯路。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐