公司分库分表使用用户id,主键后3位拼接用户id后三位,现把相关分片规则自定义简易组件使用

一、参数配置

引用者可以配置主键字段与用户字段命名,配置分片日志记录等

package com.ypshengxian.shardingslice.properties;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 描述:自动填充配置
 * Created by zjw on 2022/3/18 09:58
 */
@ConfigurationProperties(prefix = "ypsx.sharding-slice.auto-fill")
public class ShardingSliceAutoFillProperties {
    /**
     * 是否开启日志记录
     */
    public static boolean logEnabled = true;
    /**
     * 主键字段名, 数据库字段, 默认为id
     */
    public static String id = "id";
    /**
     * 用户字段名, 数据库字段, 默认为user_id
     */
    public static String userId = "user_id";
    /**
     * 库表是否以0开始
     * 例如:order_0, order_1
     * 反例:order_1, order_2
     */
    public static boolean isZeroStart = true;

    @Value("${logEnabled:true}")
    public void setLogEnabled(boolean logEnabled) {
        this.logEnabled = logEnabled;
    }

    @Value("${id:id}")
    public void setId(String id) {
        this.id = id;
    }

    @Value("${userId:user_id}")
    public void setUserId(String userId) {
        this.userId = userId;
    }

    @Value("${isZeroStart:true}")
    public void setIsZeroStart(boolean isZeroStart) {
        this.isZeroStart = isZeroStart;
    }

    public static String propertiesToString(){
        return "CartDO{" +
                "id=" + id +
                ", userId=" + userId +
                ", logEnabled=" + logEnabled +
                ", isZeroStart=" + isZeroStart +'\'' +
                '}';
    }
}

二、分片算法

需要实现ComplexKeysShardingAlgorithm接口

package com.ypshengxian.shardingslice.config;

import com.ypshengxian.shardingslice.properties.ShardingSliceAutoFillProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述:sharding 分片策略(库表通用)
 * Created by zjw on 2022/3/16 12:42
 */
@Slf4j
public class ShardingSliceComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {


    public ShardingSliceComplexKeysShardingAlgorithm() {}

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<Long> shardingValue) {
        if (ShardingSliceAutoFillProperties.logEnabled) {
            log.info("ShardingSliceAutoFillProperties:{}", ShardingSliceAutoFillProperties.propertiesToString());
        }
        if (!shardingValue.getColumnNameAndRangeValuesMap().isEmpty()) {
            return new HashSet<>(availableTargetNames);
        }
        if (ShardingSliceAutoFillProperties.logEnabled) {
            log.info("所有ShardingSliceComplexKeysShardingAlgorithm:{}", shardingValue.getColumnNameAndShardingValuesMap());
        }
        // 获取id
        Collection<Long> cartIds = shardingValue.getColumnNameAndShardingValuesMap().getOrDefault(ShardingSliceAutoFillProperties.id, new ArrayList<>(1));
        // 获取用户id
        Collection<Long> customerIds = shardingValue.getColumnNameAndShardingValuesMap().getOrDefault(ShardingSliceAutoFillProperties.userId, new ArrayList<>(1));

        // 整合id和用户id
        List<Long> ids = new ArrayList<>(16);
        ids.addAll(cartIds);
        ids.addAll(customerIds);

        List<String> shardingAlgorithm = ids.stream()
                // 对可用的表名求余数,获取到真实的表的后缀
                .map(idSuffix -> {
                    long suffix = idSuffix % 1000 % availableTargetNames.size();
                    return (ShardingSliceAutoFillProperties.isZeroStart) ? suffix : suffix + 1;
                })
                // 去重
                .distinct()
                // 转换成string
                .map(String::valueOf)
                // 获取到真实的表
                .map(tableSuffix -> availableTargetNames.stream().filter(targetName -> targetName.endsWith(tableSuffix)).findFirst().orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        if (ShardingSliceAutoFillProperties.logEnabled) {
            log.info("sharding slice result:{}", shardingAlgorithm);
        }

        return shardingAlgorithm;
    }

}

三、spring.factories启动扫描

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ypshengxian.shardingslice.config.ShardingSliceAutoConfigure

四、使用配置

spring:
  profiles:
    active: dev
  shardingsphere:
    props:
      sql.show: true # 线上环境需要关闭
    datasource:
      names: ds0
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/yipin_cart?serverTimezone=Asia/Shanghai&autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
        username: root
        password: 123456
        maxActive: 100
        maxWait: 1000
    sharding:
      default-data-source-name: ds0
      tables:
        cart:
          actual-data-nodes: ds0.cart_$->{0..7}
          database-strategy:
            complex:
              sharding-columns: user_id
              algorithm-class-name: com.ypshengxian.shardingslice.config.ShardingSliceComplexKeysShardingAlgorithm
          table-strategy:
            complex:
              sharding-columns: id,user_id
              algorithm-class-name: com.ypshengxian.shardingslice.config.ShardingSliceComplexKeysShardingAlgorithm