ShardingSphere5.x分库分表使用

2,278 阅读2分钟

ShardingSphere5.x 版本重构了很多代码以及相关文档不完善,导致个人在集成 ShardingSphere 的过程中问题不断。其中感觉最明显的是集成后 Liquibase 不能正常启动以及容易因为不熟悉 ShardingSphere5.x 导致分库分表配置错误不生效。

MAVEN项目中添加依赖

<!-- 此处引用 v5.1.0,视实际情况修改 -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.0</version>
</dependency>

配置ShardingSphere5.x

spring:
  shardingsphere:
    mode:
      # 运行模式,!!!在掌握运行模式用途之前建议默认 Memory
      type: Memory
    props:
      # 打印 ShardingSphere 执行信息,
      # 若启用未打印信息则调整使用的日志库的日志级别
      sql-show: true
    datasource: 
      # 可以用其它名称代替 ds0、ds1
      names: ds0, ds1
      ds0:
        # 支持多种数据源
        type: com.zaxxer.hikari.HikariDataSource
        # 视 JDBC 版本而定
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/sharding_demo1
        username: 数据库用户名
        password: 数据库密码
      ds1:
        # 支持多种数据源
        type: com.zaxxer.hikari.HikariDataSource
        # 视 JDBC 版本而定
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/sharding_demo2
        username: 数据库用户名
        password: 数据库密码
    rules:
      sharding:
        tables:
          # 把 xxxx_xxxx 替换成实际的表名
          xxxx_xxxx:
            database-strategy:
              standard:
                # 分片字段
                sharding-column: user_id
                # 分片策略名称,具体分片策略定义在 spring.shardingsphere.rules
                # .sharding.sharding-algorithms 路径下
                sharding-algorithm-name: xxxx-xxxx-inline-strategy
        # 默认分表策略,!!!该设置是指自定义了分片的表的默认分表策略,
        # 而不是指不分片的表的默认分表策略
        default-table-strategy:
          none:
        # 默认分库策略!!!该设置是指自定义了分片的表的默认分库策略,
        # 而不是指不分片的表的默认分库策略
        default-database-strategy:
          standard:
            sharding-column: id
            sharding-algorithm-name: id-inline-database-strategy
        sharding-algorithms:
          # id-inline-database-strategy是自定义的名称,
          # !!!最好别以下划线分隔,会有问题
          id-inline-database-strategy:
            type: INLINE
            props:
              # 该表达式是指把 id 值是偶数路由到 ds0,奇数路由到 ds1
              algorithm-expression: ds$->{id % 2}
          # xxxx-xxxx-inline-strategy是自定义的名称,
          # !!!最好别以下划线分隔,会有问题
          xxxx-xxxx-inline-strategy:
            type: INLINE
            props:
              # 该表达式是指把 user_id 值是偶数路由到 ds0,奇数路由到 ds1
              algorithm-expression: ds$->{user_id % 2}

ShardingSphere5.x 不支持默认数据源配置的解决办法

需要添加配置项 spring.shardingsphere.custom.defaultDataSourceName 定义默认数据源。

package magicodex.demo.custom.shardingsphere;

import cn.hutool.core.util.ReflectUtil;
import org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
import org.apache.shardingsphere.infra.metadata.rule.ShardingSphereRuleMetaData;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
import org.apache.shardingsphere.singletable.rule.SingleTableRule;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Map;

/**
 * <p>
 * 设置 ShardingSphereDataSource 对象里的默认数据源属性。
 * </p>
 */
@Component
@ConfigurationProperties(prefix = "spring.shardingsphere.custom", ignoreUnknownFields = true)
public class ShardingSphereDataSourcePostProcessor implements BeanPostProcessor {
    private String defaultDataSourceName;

    public void setDefaultDataSourceName(String defaultDataSourceName) {
        this.defaultDataSourceName = defaultDataSourceName;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ShardingSphereDataSource) {
            ShardingSphereDataSource dataSource = (ShardingSphereDataSource) bean;
            setDefaultDataSourceName(dataSource, defaultDataSourceName);
        }

        return bean;
    }

    /**
     * 设置默认数据源
     *
     * @param dataSource
     * @param defaultDataSourceName
     */
    private void setDefaultDataSourceName(ShardingSphereDataSource dataSource, String defaultDataSourceName) {
        ContextManager contextManager = dataSource.getContextManager();
        MetaDataContexts metaDataContexts = contextManager.getMetaDataContexts();
        Map<String, ShardingSphereMetaData> metaDataMap = metaDataContexts.getMetaDataMap();
        Collection<ShardingSphereMetaData> metaDataCollection = metaDataMap.values();

        for (ShardingSphereMetaData metaData : metaDataCollection) {
            ShardingSphereRuleMetaData ruleMetaData = metaData.getRuleMetaData();
            Collection<ShardingSphereRule> rules = ruleMetaData.getRules();

            for (ShardingSphereRule rule : rules) {
                if (rule instanceof SingleTableRule) {
                    SingleTableRule singleTableRule = (SingleTableRule) rule;
                    ReflectUtil.setFieldValue(singleTableRule, "defaultDataSource", defaultDataSourceName);
                }
            }
        }
    }

}

参考资料