shardingSphere 是一套开源的分布式数据库中间件解决方案,由 Apache 软件基金会孵化并维护。它提供了多种功能来增强传统数据库的能力,包括分库分表、读写分离、数据加密、分布式事务等。

shardingSphere主要分为两种Sharding-JDBC和Sharding-Proxy,其中Sharding-JDBC是轻量级 Java 客户端,适合作为微服务架构中的数据库访问层,以 JDBC 驱动形式提供,易于集成。而Sharding-Proxy是个中间件一样的适合非java语言接入shardingSphere,本文主要是介绍Sharding-JDBC在SpirngBoot中的使用。

引入maven包

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.1</version>
</dependency>

我这里使用的是5.x版本,和4.x版本据说有比较大的差异,不过我没有研究,后续再补充

配置文件

spring:
  # 数据源配置
  shardingsphere:
    props:
      sql-show: true
    mode:
      # 运行模式类型。可选配置:内存模式 Memory、单机模式 Standalone、集群模式 Cluster
      type: Memory
    datasource:
      names: ds_0,ds_1,big_market #数据源名称列表
      # 设置默认数据源
      defaultDataSourceName: big_market
      ds_0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/big_market_01....
        username: root
        password: 123456
      ds_1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/big_market_02.....
        username: root
        password: 123456
      big_market:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/big_market...
        username: root
        password: 123456
    rules:
      sharding:
        tables:
         # 数据源配置配置需要分库分表的表名
          raffle_activity_order:
            actualDataNodes: ds_${0..1}.raffle_activity_order_00${0..3}
            #分表
            databaseStrategy:
              standard:
                #分库依据字段
                shardingColumn: user_id
                #分表库法名称
                shardingAlgorithmName: sys_user_db_alg
            #分表    
            tableStrategy:
              standard:
                #分表依据字段
                shardingColumn: user_id
                #分表依据字段
                shardingAlgorithmName: sys_user_tbl_alg
        # 分片算法配置
        sharding-algorithms:
          #算法名称
          sys_user_db_alg:
            #表示基于类实现的
            type: CLASS_BASED
            props:
              #当分片规则基于单个分片键(Sharding Key)时,使用 standard 策略。
              strategy: standard
              #算法应用地址
              algorithmClassName: cn.liuhl.config.MyDatabaseAlgorithm
          #算法名称    
          sys_user_tbl_alg:
            type: CLASS_BASED
            props:
              strategy: standard
              algorithmClassName: cn.liuhl.config.MyTableAlgorithm#分表依据字段

配置文件比较多,一定要注意缩进,新版的idea会提示,如果出现波浪形证明配置错了,网上找了好多人的配置都是乱的,排查了挺久的问题的

分库分表算法类

package cn.liuhl.config;
​
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.springframework.stereotype.Component;
​
import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
​
/**
 * @author lhl
 * @description 自定义分表算法
 * @since 2025/3/31 下午2:53
 */
@Slf4j
public class MyTableAlgorithm implements StandardShardingAlgorithm<String> {
​
    private Properties props;
    @Override
    public Properties getProps() {
        return props;
    }
​
    @Override
    public void init() {
        log.info("分表算法加载");
        this.props = props;
    }
​
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
        int tableSize = collection.size();
        // 真实表的前缀
        String tablePrefix = preciseShardingValue.getDataNodeInfo().getPrefix();
        // 分片健的值
        long orderId = preciseShardingValue.getValue().hashCode() / 2;
        // 对分片健取模后确定位置
        long mod = orderId % tableSize;
        return tablePrefix +"00"+ mod;
    }
​
    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
        return Collections.emptyList();
    }
​
    @Override
    public String getType() {
        return "sys_user_tbl_alg";
    }
}
package cn.liuhl.config;
​
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.springframework.stereotype.Component;
​
import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
​
/**
 * @author lhl
 * @description 自定义分库算法
 * @since 2025/3/31 下午2:49
 */
@Slf4j
public class MyDatabaseAlgorithm implements StandardShardingAlgorithm<String> {
​
​
    private Properties props;
    @Override
    public Properties getProps() {
        return props;
    }
    @Override
    public void init() {
        log.info("分库算法加载");
        this.props = props;
    }
​
    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> preciseShardingValue) {
        int tableSize = collection.size();
        // 真实表的前缀
        String tablePrefix = preciseShardingValue.getDataNodeInfo().getPrefix();
        // 分片健的值
        long orderId = preciseShardingValue.getValue().hashCode();
        // 对分片健取模后确定位置
        long mod = orderId % tableSize;
        return tablePrefix + mod;
    }
​
    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<String> rangeShardingValue) {
        return Collections.emptyList();
    }
​
​
​
    @Override
    public String getType() {
        return "sys_user_db_alg";
    }
}

目前我这个配置比较简单,主要就是按userId的hashCode进行取模计算,真实情况还得基于具体的业务去配置,这里只是做个参考。

单元测试

对于有分片的数据就插入到了具体的库表中

对于没有分片字段的sql就会走广播,也就是说会查询全部的库表

强制分片(指定数据库扫库)

后续。。。。

分库分表事务处理

后续。。。。