最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

shardingsphere-jdbc5.5.1分庫分表實戰(zhàn)

 更新時間:2026年02月03日 09:10:02   作者:荒古廢體  
本文主要介紹了shardingsphere-jdbc5.5.1分庫分表實戰(zhàn),解決了分表和讀寫分離的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

本文章主要是:
分享分庫分表的demo案例,技術選型,數(shù)據(jù)量達到4億用戶。后面待補充詳情…

背景:

  • 如何設計一個支持海浪訂單存儲的高擴展性能?
  • 在做分庫分表時,sharding key 的依據(jù)?
  • 在做分庫分表時,基于hash取模和一致性hash的數(shù)據(jù)分片是如何實現(xiàn)的?
  • 如何通過虛擬節(jié)點提高均衡度?

前言:

高性能數(shù)據(jù)庫集群的第一種方式是“讀寫分離”,第二種方式是“數(shù)據(jù)庫分片”。

版本依賴:

主要版本:

Springboot 3.3.4

shardingsphere-jdbc 5.5.1

mybatis-plus-spring-boot3-starter 3.5.8

有三種方案:

  1. 只分庫不分表
  2. 只分表不分庫
  3. 既分庫又分表

本帖子只記錄單表多庫,多庫多表的例子。

功能實現(xiàn)

目錄結構如下:

maven版本

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atdx</groupId>
    <artifactId>sharding_sphere</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shardingSphere</name>

    <description>分庫分表案例</description>

    <properties>
        <java.version>17</java.version>
        <snakeyaml.version>2.2</snakeyaml.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.32</version>
        </dependency>

        <!-- 解決自帶 snakeyaml 版本過低的問題-->
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>${snakeyaml.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc</artifactId>
            <version>5.5.1</version>
            <!-- 排除沖突的 SnakeYAML -->
            <exclusions>
                <exclusion>
                    <groupId>org.yaml</groupId>
                    <artifactId>snakeyaml</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
            <scope>runtime</scope>
        </dependency>

        <!-- MyBatis Plus Spring Boot 3兼容版本 -->
<!--        <dependency>-->
<!--            <groupId>com.baomidou</groupId>-->
<!--            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>-->
<!--            <version>3.5.8</version>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.yaml</groupId>
                <artifactId>snakeyaml</artifactId>
                <version>${snakeyaml.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml

########### V1 實現(xiàn)了 單庫,多個表 #############
spring:
  application:
    name: sharding-jdbc-demo
  # 使用ShardingSphere Driver + 獨立配置文件
  # 配置數(shù)據(jù)庫的連接信息
  datasource:
    #動態(tài)數(shù)據(jù)源配置
    dynamic:
      #主數(shù)據(jù)源,默認啟用
      primary: master
      datasource:
        #數(shù)據(jù)源 本地庫
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/wedding_bill_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true&allowMultiQueries=true
          username: root
          password: rootroot
          # 分庫分表邏輯
        shardingSphere:
          driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
          url: jdbc:shardingsphere:classpath:sharding.yaml
          # 移除username和password,因為在sharding.yaml中配置
#          username: root
#          password: rootroot


# MyBatis Plus 配置
mybatis-plus:
  mapper-locations: classpath:mapper/shard/**/*.xml
  type-aliases-package: com.**.**.entity
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      # 雪花算法
      id-type: ASSIGN_ID

# 分庫分表的密鑰 用于手機號接收加密和解密用
sharding:
  sphere:
    secretKey:
      phoneNum: T9ycWqd/VgQ32x0MRxU0cQ==

1,單庫多表

sharding.yaml 配置如下

####################### V1 第一版 簡單實現(xiàn)單個庫,每個庫有3個表的 分庫邏輯############################################################################
dataSources:
  ds:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/db_user?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot

rules:
  - !SHARDING
    tables:
      t_user:
        actualDataNodes: ds.t_user_$->{0..2}
        tableStrategy:
          standard:
            # 分表字段 phone_num 根據(jù)手機號進行分表
            shardingColumn: phone_num
            # 保持一致性
            shardingAlgorithmName: db-user-inline
    shardingAlgorithms:
      db-user-inline:
        type: INLINE
        props:
          # 根據(jù)手機號取模 hash 運算
          algorithm-expression: t_user_$->{Math.abs(phone_num.hashCode()) % 3}
    defaultDatabaseStrategy:
      none:

props:
  sql-show: true

自動生成手機號工具類:

package com.at.ss.shardingsphere.utils;

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 手機號生成工具類
 * @author daxigua
 */
public class PhoneNumberGenerator {

    // 手機號前綴(中國大陸)
    private static final String[] PHONE_PREFIXES = {
            "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
            "145", "147", "149", "150", "151", "152", "153", "155", "156", "157", "158", "159",
            "165", "166", "167", "170", "171", "172", "173", "174", "175", "176", "177", "178",
            "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
            "191", "198", "199"
    };

    private static final Random random = new Random();
    private static final AtomicLong counter = new AtomicLong(1000000000L);

    /**
     * 生成隨機手機號
     */
    public static String generateRandomPhone() {
        String prefix = PHONE_PREFIXES[random.nextInt(PHONE_PREFIXES.length)];
        String suffix = String.format("%08d", random.nextInt(100000000));
        return prefix + suffix;
    }

    /**
     * 生成序列化手機號(避免重復)
     */
    public static String generateSequentialPhone() {
        long number = counter.getAndIncrement();
        String prefix = PHONE_PREFIXES[(int) (number % PHONE_PREFIXES.length)];
        String suffix = String.format("%08d", number % 100000000);
        return prefix + suffix;
    }

    /**
     * 批量生成手機號
     */
    public static List<String> generateBatchPhones(int count, boolean sequential) {
        Set<String> phones = new HashSet<>(count) {
        };
        for (int i = 0; i < count; i++) {
            if (sequential) {
                phones.add(generateSequentialPhone());
            } else {
                phones.add(generateRandomPhone());
            }
        }
        return new ArrayList<>( phones);
    }
}

雪花算法ID 工具類

package com.at.ss.shardingsphere.utils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class SnowflakeIdGenerator {

    // ==============================Fields===========================================
    /** 開始時間截 (2024-01-01) */
    private final long startTimestamp = 1704067200000L;

    /** 機器id所占的位數(shù) */
    private final long workerIdBits = 5L;

    /** 數(shù)據(jù)標識id所占的位數(shù) */
    private final long datacenterIdBits = 5L;

    /** 支持的最大機器id,結果是31 (這個移位算法可以很快的計算出幾位二進制數(shù)所能表示的最大十進制數(shù)) */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

    /** 支持的最大數(shù)據(jù)標識id,結果是31 */
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

    /** 序列在id中占的位數(shù) */
    private final long sequenceBits = 12L;

    /** 機器ID向左移12位 */
    private final long workerIdShift = sequenceBits;

    /** 數(shù)據(jù)標識id向左移17位(12+5) */
    private final long datacenterIdShift = sequenceBits + workerIdBits;

    /** 時間截向左移22位(5+5+12) */
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    /** 生成序列的掩碼,這里為4095 (0b111111111111=0xfff=4095) */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    /** 工作機器ID(0~31) */
    private long workerId;

    /** 數(shù)據(jù)中心ID(0~31) */
    private long datacenterId;

    /** 毫秒內(nèi)序列(0~4095) */
    private long sequence = 0L;

    /** 上次生成ID的時間截 */
    private long lastTimestamp = -1L;

    // ==============================Constructors=====================================
    /**
     * 構造函數(shù)
     */
    public SnowflakeIdGenerator() {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    // ==============================Methods==========================================
    /**
     * 獲得下一個ID (該方法是線程安全的)
     * @return SnowflakeId
     */
    public synchronized long nextId() {
        long timestamp = timeGen();

        // 如果當前時間小于上一次ID生成的時間戳,說明系統(tǒng)時鐘回退過這個時候應當拋出異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        // 如果是同一時間生成的,則進行毫秒內(nèi)序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            // 毫秒內(nèi)序列溢出
            if (sequence == 0) {
                // 阻塞到下一個毫秒,獲得新的時間戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        }
        // 時間戳改變,毫秒內(nèi)序列重置
        else {
            sequence = 0L;
        }

        // 上次生成ID的時間截
        lastTimestamp = timestamp;

        // 移位并通過或運算拼到一起組成64位的ID
        return ((timestamp - startTimestamp) << timestampLeftShift) //
                | (datacenterId << datacenterIdShift) //
                | (workerId << workerIdShift) //
                | sequence;
    }

    /**
     * 阻塞到下一個毫秒,直到獲得新的時間戳
     * @param lastTimestamp 上次生成ID的時間截
     * @return 當前時間戳
     */
    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    /**
     * 返回以毫秒為單位的當前時間
     * @return 當前時間(毫秒)
     */
    protected long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * 生成指定數(shù)量的ID數(shù)組(用于測試分庫分表)
     */
    public long[] generateIds(int count) {
        long[] ids = new long[count];
        for (int i = 0; i < count; i++) {
            ids[i] = nextId();
        }
        return ids;
    }

    /**
     * 生成指定數(shù)量的ID并放入ArrayList集合
     */
    public List<Long> generateIdList(int count) {
        List<Long> idList = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            idList.add(nextId());
        }
        return idList;
    }

    /**
     * 生成指定數(shù)量的ID并放入LinkedList集合
     */
    public List<Long> generateIdLinkedList(int count) {
        List<Long> idList = new LinkedList<>();
        for (int i = 0; i < count; i++) {
            idList.add(nextId());
        }
        return idList;
    }

    /**
     * 生成指定數(shù)量的ID并放入線程安全的CopyOnWriteArrayList集合
     */
    public List<Long> generateIdConcurrentList(int count) {
        List<Long> idList = new CopyOnWriteArrayList<>();
        for (int i = 0; i < count; i++) {
            idList.add(nextId());
        }
        return idList;
    }

    /**
     * 批量生成ID并放入指定集合(通用方法)
     */
    public <T extends Collection<Long>> T generateIdsToCollection(int count, T collection) {
        for (int i = 0; i < count; i++) {
            collection.add(nextId());
        }
        return collection;
    }

    /**
     * 生成ID并分批放入多個集合(用于分庫分表測試)
     */
    public Map<Integer, List<Long>> generateIdsForSharding(int totalCount, int shardCount) {
        Map<Integer, List<Long>> shardMap = new HashMap<>();

        // 初始化每個分片的集合
        for (int i = 0; i < shardCount; i++) {
            shardMap.put(i, new ArrayList<>());
        }

        // 生成ID并根據(jù)分片規(guī)則分配到不同集合
        for (int i = 0; i < totalCount; i++) {
            long id = nextId();
            int shardIndex = (int) (id % shardCount); // 簡單的取模分片
            shardMap.get(shardIndex).add(id);
        }

        return shardMap;
    }

    /**
     * 異步生成ID集合(高性能版本)
     */
    public CompletableFuture<List<Long>> generateIdsAsync(int count) {
        return CompletableFuture.supplyAsync(() -> generateIdList(count));
    }

    /**
     * 流式生成ID集合(Java 8 Stream API)
     */
    public List<Long> generateIdsStream(int count) {
        return Stream.generate(this::nextId)
                .limit(count)
                .collect(Collectors.toList());
    }
}

測試方法:

  /**
     * 測試單庫分表,每個庫3張表
     */
    @Test
    public void singleDatabaseWithTablePartitioning(){
        SnowflakeIdGenerator snowflakeIdGenerator = new SnowflakeIdGenerator();
        List<String> phones = PhoneNumberGenerator.generateBatchPhones(500, false);
        ArrayList<Long> snowflakeIds = snowflakeIdGenerator.generateIdsToCollection(500, new ArrayList<>());
        for (int i = 0; i < 500; i++) {
            User user = new User();
            user.setId(snowflakeIds.get(i));
            user.setUname("張三豐");
            user.setPhoneNum(phones.get(i));
            // 驗證分表計算
            String tableName = this.calculateTableName(user.getPhoneNum());
            log.info("手機號 " + user.getPhoneNum() + " 應該分配到表: " + tableName);
            userMapper.insert(user);
            log.info("插入用戶ID: " + user.getId() + ", 手機號: " + user.getPhoneNum());
        }
    }
    /**
     * 計算手機號對應的分表
     */
    public String calculateTableName(String phone) {
        String cleanPhone = phone.replaceAll("[^0-9]", "");
        int tableIndex = Math.abs(cleanPhone.hashCode()) % 3;
        return "t_user_" + tableIndex;
    }

2,多庫多表

application.yml的配置和上面一樣

sharding.yaml 配置如下

######################## V2 第二版 實現(xiàn)10個庫,每個庫有3個表的 分庫邏輯############################################################################
dataSources:
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_0?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_2:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_3:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_3?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_4:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_4?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_5:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_5?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_6:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_6?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_7:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_7?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_8:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_8?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot
  ds_9:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/db_user_9?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
    username: root
    password: rootroot

rules:
  - !SHARDING
    tables:
      t_stu:
        actualDataNodes: ds_$->{0..9}.t_stu_$->{0..2}
        # 分庫策略 - 基于ID取模
        databaseStrategy:
          standard:
            shardingColumn: id
            shardingAlgorithmName: database-sharding
        # 分表策略
        tableStrategy:
          standard:
            shardingColumn: phone_num
            shardingAlgorithmName: table-sharding

      # 教師表 分庫分表策略
      t_tea:
        actualDataNodes: ds_$->{0..9}.t_tea_$->{0..2}
        # 分庫策略 - 基于ID取模
        databaseStrategy:
          standard:
            shardingColumn: id
            shardingAlgorithmName: database-sharding
        # 分表策略
        tableStrategy:
          standard:
            shardingColumn: phone_num
            shardingAlgorithmName: table-sharding

    shardingAlgorithms:
      # 分庫算法取模
      database-sharding:
        type: CLASS_BASED
        props:
          strategy: standard
          algorithmClassName: com.at.ss.shardingsphere.algorithm.DatabaseShardingAlgorithm
      # 分表算法 - 修正算法名稱
      table-sharding:
        type: CLASS_BASED
        props:
          strategy: standard
          algorithmClassName: com.at.ss.shardingsphere.algorithm.MobileHashShardingAlgorithm

props:
  sql-show: true

數(shù)據(jù)庫的雪花ID分庫算法如下

package com.at.ss.shardingsphere.algorithm;

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 java.util.Collection;

/**
 * @author daxigua 基于雪花算法ID的分庫算法
 */
@Slf4j
public class DatabaseShardingAlgorithm implements StandardShardingAlgorithm<Long> {

/*  根據(jù)雪花算法 ID 取模進行 分庫 */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        Long id = shardingValue.getValue();
        // 雪花算法ID取模分庫
        int databaseIndex = Math.abs(id.intValue() % availableTargetNames.size());
        for (String databaseName : availableTargetNames) {
            if (databaseName.endsWith("_" + databaseIndex)) {
                log.info("最終落到數(shù)據(jù)庫是====>>>> :{}" , databaseName);
                return databaseName;
            }
        }
        throw new IllegalArgumentException("未找到對應的分庫,計算的庫索引: " + databaseIndex);
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        // 范圍查詢返回所有的庫
        log.info("范圍查詢返回所有的庫:{}" , availableTargetNames);
        return availableTargetNames;
    }
}

分表的算法如下:

package com.at.ss.shardingsphere.algorithm;

import com.at.ss.shardingsphere.utils.CryptoUtils;
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 java.util.Collection;

/**
 * @author daxigua 根據(jù)加密后的手機號進行分表
 *  手機號分表算法
 */
@Slf4j
public class MobileHashShardingAlgorithm implements StandardShardingAlgorithm<String> {
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) {
        String phoneNum = shardingValue.getValue();
        // 基于手機號計算分片表位置
        int tableIndex = CryptoUtils.calculateTableShard(phoneNum);
        for (String tableName : availableTargetNames) {
            if (tableName.endsWith("_" + tableIndex)){
                log.info("手機號 " + phoneNum + " 應該分配到表: " + tableName);
                return tableName;
            }
        }
        throw new IllegalArgumentException("未找到對應的分表,計算的分表索引: " + tableIndex);
    }


    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<String> rangeShardingValue) {
        // 范圍查詢返回所有的表,確保能查詢到所有的表數(shù)據(jù)
        log.info("范圍查詢,返回所有的表 :{} " , availableTargetNames);
        return availableTargetNames;
    }
}

3,sql

--------------------------------V1 - 單庫多表進行拆分 【水平拆分】----------------------------------------------------
-- 創(chuàng)建數(shù)據(jù)庫 1個庫都,每個都創(chuàng)建3個表
CREATE DATABASE db_user;
USE db_user;

-- 創(chuàng)建表
CREATE TABLE t_user_0(
    id        BIGINT PRIMARY KEY,
    uname     VARCHAR(50),
    phone_num VARCHAR(128)
);

CREATE TABLE t_user_1(
    id        BIGINT PRIMARY KEY,
    uname     VARCHAR(50),
    phone_num VARCHAR(128)
);

CREATE TABLE t_user_2(
    id        BIGINT PRIMARY KEY,
    uname     VARCHAR(50),
    phone_num VARCHAR(128)
);


--------------------------------- V2 - 多庫多表 3個庫,每個庫3個表---------------------------------------------------
-- 創(chuàng)建數(shù)據(jù)庫 10個庫都,每個都創(chuàng)建3個表,并且根據(jù)雪花ID取模進行分庫,根據(jù)加密后的手機號取hash取模
CREATE DATABASE db_user_0;
CREATE DATABASE db_user_1;
CREATE DATABASE db_user_2;
CREATE DATABASE db_user_3;
CREATE DATABASE db_user_4;
CREATE DATABASE db_user_5;
CREATE DATABASE db_user_6;
CREATE DATABASE db_user_7;
CREATE DATABASE db_user_8;
CREATE DATABASE db_user_9;

-- 創(chuàng)建表
CREATE TABLE t_stu_0(
    id        BIGINT PRIMARY KEY,
    uname     VARCHAR(50),
    phone_num VARCHAR(128),
    subject_name VARCHAR(50)
);

CREATE TABLE t_stu_1(
    id        BIGINT PRIMARY KEY,
    uname     VARCHAR(50),
    phone_num VARCHAR(128),
    subject_name VARCHAR(50)
);

CREATE TABLE t_stu_2(
    id        BIGINT PRIMARY KEY,
    uname     VARCHAR(50),
    phone_num VARCHAR(128),
    subject_name VARCHAR(50)
);


--------------------------------- V2 - 多庫多表 10個庫,每個庫3個表---------------------------------------------------
-- 主要測試相同的根據(jù)手機號分庫分表策略
CREATE TABLE t_tea_0(
    id           BIGINT PRIMARY KEY,
    uname        VARCHAR(50),
    phone_num    VARCHAR(128),
    subject_name VARCHAR(50)
);

CREATE TABLE t_tea_1(
    id           BIGINT PRIMARY KEY,
    uname        VARCHAR(50),
    phone_num    VARCHAR(128),
    subject_name VARCHAR(50)
);

CREATE TABLE t_tea_2(
    id           BIGINT PRIMARY KEY,
    uname        VARCHAR(50),
    phone_num    VARCHAR(128),
    subject_name VARCHAR(50)
);

問題

1.為什么要分庫分表?

  • 分庫解決的是并發(fā)量大的問題。通過增加數(shù)據(jù)庫的實例數(shù)來提供更多的可用連接,提高系統(tǒng)的并發(fā)性能,提高查詢效率
  • 分表的解決的是數(shù)據(jù)量大的問題,存儲和查詢的性能已經(jīng)為瓶頸,此時做了很多的優(yōu)化,依然沒有效果的話。

數(shù)據(jù)量大,就分表,并發(fā)高就分庫

2. 如何選擇 sharing key ?

Sharding key :分表的字段,選擇 sharing key 最重要的參考因素:我們的業(yè)務是如何訪問數(shù)據(jù)的。

假設app的訂單ID 【orderId】作為 sharding key 行不行?公司的營收來源于用戶,而用戶對于訂單最高的訪問是 app中“我的訂單”頁面,此時的查詢條件:用戶ID。但是我們分片的依據(jù)是orderId ,沒發(fā)查詢。強行查詢的只能是查詢所有的分片,合并查詢結果,效率低,沒法分頁。

如果把userId作為sharing key 行不行?此時用戶在“我的訂單”頁面正好可以使用分片鍵,一個用戶對應的訂單信息都在一個分片中,

因為分片是使用User ID,此時效率最高。直接去對應分片查詢就行了。

可以理解:產(chǎn)品靠什么賺錢,主要用到查詢的條件是什么

3.有使用order ID 進行查詢的場景怎么辦?

網(wǎng)上說是下面這個方法 ,還未驗證
在生成訂單ID的時候,可以用戶ID的后幾位作為訂單ID的一部分。比如18位的訂單號,第15-18位是用戶的后4位,此時按照訂單ID查詢的時候,可以根據(jù)訂單ID的用戶ID找到分片。

遇到的問題:

1,shardingsphere-jdbc 5.5.1 和 spring-boot-starter-parent 2.7.18【spring-boot-starter-parent 3.3.4】寫法不一樣

2,shardingsphere-jdbc 5.5.1 如果存在多數(shù)據(jù)源的情況下,mybatis-plus-spring-boot3-starter 3.5.8 如果低于3.5.8會導致多數(shù)據(jù)源和分庫分表數(shù)據(jù)源沖突不適配
3,shardingsphere-jdbc 5.5.1 的 snakeyaml 自帶版本是2.0,項目配置多庫多表不支持,后面需要先排除再引入2.2 多依賴

到此這篇關于shardingsphere-jdbc5.5.1分庫分表實戰(zhàn)的文章就介紹到這了,更多相關shardingsphere-jdbc 分庫分表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java DateUtil工具類時間戳類型轉換詳解

    java DateUtil工具類時間戳類型轉換詳解

    這篇文章主要為大家詳細介紹了java DateUtil工具類時間戳類型轉換的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Java字節(jié)碼增強技術知識點詳解

    Java字節(jié)碼增強技術知識點詳解

    在本篇文章里小編給大家整理的是一篇關于Java字節(jié)碼增強技術知識點詳解內(nèi)容,有興趣的朋友可以跟著學習下。
    2021-08-08
  • Java中stream處理中map與flatMap的比較和使用案例

    Java中stream處理中map與flatMap的比較和使用案例

    這篇文章主要介紹了Java中stream處理中map與flatMap的比較和使用案例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Java中this關鍵字的用法詳解

    Java中this關鍵字的用法詳解

    我知道很多朋友都和我一樣,在JAVA程序中似乎經(jīng)常見到this,自己也偶爾用到它,但是到底this該怎么用,卻心中無數(shù),下面這篇文章主要給大家介紹了關于Java中this關鍵字用法的相關資料,需要的朋友可以參考下
    2023-05-05
  • Mybatis generator修改Mapper.java文件實現(xiàn)詳解

    Mybatis generator修改Mapper.java文件實現(xiàn)詳解

    這篇文章主要為大家介紹了Mybatis generator修改Mapper.java文件實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • jvm調(diào)優(yōu)的幾種場景(小結)

    jvm調(diào)優(yōu)的幾種場景(小結)

    本文主要介紹了jvm調(diào)優(yōu)的幾種場景,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • @SpringBootConfiguration重復加載報錯問題解決

    @SpringBootConfiguration重復加載報錯問題解決

    @SpringBootApplication?注解的?exclude?屬性用于排除特定的自動配置類,而不是用于排除主配置類本身,因此,不能通過?exclude?屬性來排除主配置類的加載,這篇文章主要介紹了@SpringBootConfiguration重復加載報錯,需要的朋友可以參考下
    2024-08-08
  • 詳解Java ES多節(jié)點任務的高效分發(fā)與收集實現(xiàn)

    詳解Java ES多節(jié)點任務的高效分發(fā)與收集實現(xiàn)

    ElasticSearch 是一個高可用開源全文檢索和分析組件。提供存儲服務,搜索服務,大數(shù)據(jù)準實時分析等。一般用于提供一些提供復雜搜索的應用
    2021-06-06
  • Java內(nèi)存模型之happens-before概念詳解

    Java內(nèi)存模型之happens-before概念詳解

    happens-before原則非常重要,它是判斷數(shù)據(jù)是否存在競爭、線程是否安全的主要依據(jù),依靠這個原則,我們解決在并發(fā)環(huán)境下兩操作之間是否可能存在沖突的所有問題。下面我們就一個簡單的例子稍微了解下happens-before知識,感興趣的朋友一起看看吧
    2021-06-06
  • 從JVM的內(nèi)存管理角度分析Java的GC垃圾回收機制

    從JVM的內(nèi)存管理角度分析Java的GC垃圾回收機制

    這篇文章主要介紹了從JVM的內(nèi)存管理角度分析Java的GC垃圾回收機制,帶有GC是Java語言的重要特性之一,需要的朋友可以參考下
    2015-11-11

最新評論

曲麻莱县| 筠连县| 南部县| 浦江县| 噶尔县| 青岛市| 益阳市| 永济市| 平果县| 馆陶县| 湖口县| 阆中市| 堆龙德庆县| 碌曲县| 扬州市| 阿拉善左旗| 靖边县| 沁水县| 永康市| 天津市| 清徐县| 定南县| 孟津县| 洛阳市| 金山区| 德清县| 荆州市| 云安县| 四会市| 神农架林区| 黄陵县| 个旧市| 新邵县| 大城县| 肥乡县| 连平县| 谷城县| 伊金霍洛旗| 洛川县| 康平县| 天等县|