【经验分享】ShardingSphere+Springboot-04:自定义分片算法(COMPLEX/STANDARD)

news2024/11/15 4:23:37

文章目录

      • 3.4 CLASS_BASED 自定义类分片算法
        • 3.4.1 复杂分片自定义算法(strategy=COMPLEX )
        • 3.4.2 STANDARD 标准分片自定义算法
        • ## 进阶:star: 自定义算法+范围查询优化

3.4 CLASS_BASED 自定义类分片算法

3.4.1 复杂分片自定义算法(strategy=COMPLEX )

通过配置分片策略类型和算法类名,实现自定义扩展。 掌握自定义类算法就算法完全掌握了分片算法的精髓,可以根据业务需求灵活配置分片规则。

类型:CLASS_BASED

可配置属性:

属性名称数据类型说明
strategyString分片策略类型,支持 STANDARD、COMPLEX 或 HINT(不区分大小写)
algorithmClassNameString分片算法全限定名

官方文档给出了一个参考案例如下,没有太多的说明,这尝试用自定义分片算法重新实现[3.3.1]中的行表达式分表规则

package org.apache.shardingsphere.sharding.fixture;

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;

public final class ClassBasedStandardShardingAlgorithmFixture implements StandardShardingAlgorithm<Integer> {

@Override
public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Integer> shardingValue) {
  for (String each : availableTargetNames) {
      if (each.endsWith(String.valueOf(shardingValue.getValue() % 4))) {
          return each;
      }
  }
  return null;
}

@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Integer> shardingValue) {
  return availableTargetNames;
}
}

实现目标:根据用户类型user_type和部门dep_id进行复杂分库分表

编写分片算法类:

  1. 根据分片策略类型( STANDARD、COMPLEX 或 HINT)实现对应的算法接口,这里需要用到的复杂算法的接口

    image-20240809111027491

  2. 实现必须的方法,这里核心关注doSharding方法,编写思路记录如下

    • 获取列名和分片值的映射(必备的,获取了才能根据分片键值计算数据源嘛
    • (可选)获取逻辑表名、范围值映射
    • 获取分片键值,并计算得到真实数据源

完整算法类:

package com.zhc.shard.algo;

import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;

import java.util.*;

/**
 * @Author zhuhuacong
 * @Date: 2024/08/09/ 11:07
 * @description
 */
@Slf4j
public class UserTypeDepIdAlgorithm implements ComplexKeysShardingAlgorithm<String> {
    // 定义列名常量
    private static final String col1 = "user_type";
    private static final String col2 = "dep_id";

    /**
     * 实现分片逻辑
     * 当分片条件存在时,根据给定的分片键计算出特定的数据源
     * 如果无法计算出合适的分片结果,则抛出异常
     *
     * @param collection               数据源集合(这里是分表策略,所以这里是真实表集合
     * @param complexKeysShardingValue 分片条件对象
     * @return 分片后的数据源名称列表
     * @throws RuntimeException 当无法得到合适的分片结果时
     */
    @Override
    public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
        // 获取逻辑表名
        String logicTableName = complexKeysShardingValue.getLogicTableName();

        // 获取列名和分片值的映射
        Map columnNameAndShardingValuesMap = complexKeysShardingValue.getColumnNameAndShardingValuesMap();

        // 获取列名和范围值的映射(未用到)
        Map columnNameAndRangeValuesMap = complexKeysShardingValue.getColumnNameAndRangeValuesMap();

        // 获取分片键值
        List c1UserType = (List) columnNameAndShardingValuesMap.get(col1);
        List c2DepId = (List) columnNameAndShardingValuesMap.get(col2);

        // 如果任一分片键存在,则进行分片计算
        if (Optional.ofNullable(c1UserType).isPresent() || Optional.ofNullable(c2DepId).isPresent()) {
            // 【算法核心】 根据分片键值计算数据源索引
            long userType = c1UserType.get(0) != null ? Long.parseLong(c1UserType.get(0).toString()) : 0;
            long depId = c2DepId.get(0) != null ? Long.parseLong(c2DepId.get(0).toString()) : 0;
            long shardingId = ((userType + depId) % 2);
            String tableName = logicTableName + "_" + shardingId;
            log.info("userType:{};shardingId:{};余数{};真是表名{}", userType, depId, shardingId , tableName);

            // 返回计算后的数据源名称
            return Collections.singletonList(tableName);
        }
        // 如果无法得到合适的分片结果,则记录日志并抛出异常
        log.info("没有得到合适的分片结果=:表名{},参数:{}", collection, columnNameAndShardingValuesMap);
        throw new RuntimeException("没有得到合适的分片结果");
    }


    @Override
    public Properties getProps() {
        return null;
    }

    @Override
    public void init(Properties properties) {

    }
}

进行测试

分表策略运行正确

image-20240809114449222

3.4.2 STANDARD 标准分片自定义算法

快速实现,表结构还是参考前面的打卡表。要求根据早中晚三个时段的打卡时间进行分表,分别存入

stu_clock_am、stu_clock_noon、stu_clock_eve;

yaml配置如下

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          # 打卡表
          stu_clock:
            actual-data-nodes: dsmain.stu_clock_am,dsmain.stu_clock_noon,dsmain.stu_clock_eve
            key-generate-strategy:
              column: id
              key-generator-name: snowflake
            table-strategy:
              standard:
                sharding-column: clockin_time
                sharding-algorithm-name: stu_clock_class_algo
        # 配置分片算法
        sharding-algorithms:
          stu_clock_class_algo:
            type: CLASS_BASED
            props:
              #分片策略类型,支持 STANDARD、COMPLEX 或 HINT(不区分大小写)
              strategy: STANDARD
              # 分片算法全限定名
              algorithmClassName: com.zhc.shard.algo.StuClockClassAlgorithm

算法代码

package com.zhc.shard.algo;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Range;
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.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Properties;

/**
 * @Author zhuhuacong
 * @Date: 2024/08/09/ 14:56
 * @description StuClockClassAlgorithm
 */
@Slf4j
public class StuClockClassAlgorithm implements StandardShardingAlgorithm<Date> {


    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
        String logicTableName = shardingValue.getLogicTableName();
        Date date = shardingValue.getValue();
        LocalDateTime localDateTime = DateUtil.toLocalDateTime(date);
        int hour = localDateTime.getHour();
        log.info("logicTableName: {} value: {} hour {}", logicTableName, date, hour);
        String actualTableName =null;
        if (hour > 15){
            actualTableName =  logicTableName + "_eve";
        } else if (hour > 10 ){
            actualTableName =  logicTableName + "_noon";
        } else {
            actualTableName =  logicTableName + "_am";
        }
        if (availableTargetNames.contains(actualTableName)){
            return actualTableName;
        }
        // 如果无法得到合适的分片结果,则记录日志并抛出异常
        log.info("没有得到合适的分片结果:表名{},参数:{}", shardingValue, shardingValue);
        throw new RuntimeException("没有得到合适的分片结果");
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> shardingValue) {
        return availableTargetNames;
    }

    @Override
    public Properties getProps() {
        return null;
    }

    @Override
    public void init(Properties properties) {

    }
}

结果测试,

生成随机打卡时间,观察是否正确入库

image-20240809153044358

结果符合预期

## 进阶⭐️ 自定义算法+范围查询优化

可以发现,StandardShardingAlgorithm接口还有一个同样叫doSharding的接口,

    /**
     * Sharding.
     *
     * @param availableTargetNames available data sources or table names
     * @param shardingValue sharding value
     * @return sharding results for data sources or table names
     */
    Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<T> shardingValue);

传入的参数是一个带有范围(上下界限)shardingValue,一个是可用的真实表集合availableTargetNames,返回参数就是需要查询的目标表列表。

只要根据实际业务逻辑实现方法体内容即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1996494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows 10 /11 系统上安装Arc浏览器!超详细的教程

Arc浏览器在在发布以后&#xff0c;给人留下了相当不错的第一印象。 简洁的界面设计,巧妙的操作逻辑,使用过后让人爱不释手,体验出众&#xff01;目前官方提供了Windows 11 和 Mac版 官方下载&#xff1a;【链接直达】 如果你是Windows 10系统&#xff0c;由于官方没有直接提…

加固三防笔记本电脑:保护数据安全的首选设备

随着信息技术的飞速发展&#xff0c;笔记本电脑早已成为现代生活中不可或缺的工具。然而&#xff0c;普通的笔记本电脑无法适应一些特殊的环境&#xff0c;在数据安全保护方面也有着一定的风险。加固三防笔记本电脑则是保护数据安全的首选设备。下面将介绍加固三防笔记本电脑的…

掌控150+KOC账号!游戏厂商深掘ChinaJoy余温,热度再飙升!

4天36.7万人次&#xff0c;抖音话题总播放次数达到10.9亿&#xff01; ChinaJoy&#xff08;以下简称CJ&#xff09;官方给出了第21届CJ的参观总人次和线上流量数据&#xff0c;展现了其应有的“顶流”热度。 作为全球数字娱乐领域最具知名度与影响力的年度盛会&#xff0c;202…

springmvc框架 dispacherServelet容器组件调用

服务器启动时&#xff0c;tomcat创建并自动装配所有生成对象&#xff1a;spring容器放在服务器应用全局中&#xff0c;springmvc容器被放在dispacherServlet容器中。注解解析器在dispacherServlet创建时赋予它识别相关注解并作出相应操作的能力。 浏览器发送请求req&#xff0c…

养老院老人健康信息管理系统 /养老院管理系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…

达梦数据库 DMFLDR的使用

达梦的DMFLDR使用 1.背景2.要求3.实验步骤3.1 参数简介3.2 控制文件3.3 数据文件编写3.4 创建表3.5 执行装载程序3.6 查看运行结果3.7 数据导出控制文件编写3.8 数据导出命令3.9 行列分隔符 4.实验结论 1.背景 用户通过使用快速装载工具能够把按照一定格式排序的文本数据以简单…

门店收银系统源码+同城即时零售多商户入驻商城源码

一、我们为什么要开发这个系统&#xff1f; 1. 商户经营现状 “腰尾部”商户&#xff0c;无小程序运营能力&#xff1b;自营私域商城流量渠道单一&#xff1b;无法和线下收银台打通&#xff0c;库存不同步&#xff0c;商品不同步&#xff0c;订单不同步&#xff1b; 2.平台服…

SpringBoot-application.properties为对象赋值

简单对象赋值 第一种方式 首先让该Bean交由Spring管理,然后加上ConfigurationProperties(prefix"前缀") <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId>&l…

PCIe学习笔记(19)

TLP Prefix&#xff08;前缀&#xff09;规则 以下规则适用于任何包含TLP Prefix的TLP: •对于任何TLP, TLP第0字节的Fmt[2:0]字段值为100b表示存在TLP Prefix, Type[4]位表示TLP Prefix的类型。 ◦Type[4]位的值为0b表示存在Local TLP Prefix ◦Type[4]位的值为1b表示存在…

一、Matlab基础

文章目录 一、Matlab界面二、Matlab窗口常用命令三、Matlab的数据类型3.1 数值类型3.2 字符和字符串3.3 逻辑类型3.4 函数句柄3.5 结构类型3.6 细胞数组 四、Matlab的运算符4.1 算术运算符4.2 关系运算符4.3 逻辑运算4.4 运算符优先级 五、Matlab的矩阵5.1 矩阵的建立5.2 矩阵的…

解决vscode连接远程服务器时一直要求输入密码的问题

今天在用vscode连接我的Linux服务器时&#xff0c;输入密码后并没有成功登录&#xff0c;而是不断的弹出密码输入框。如果有遇到相同问题的同学可以试试下面的方法 1.点击查看&#xff0c;打开命令面板 2.终止服务器 选中自己的服务器&#xff0c;然后会让你输入密码 3.重新登…

sqlserver一列转多行

文章目录 sqlserver一列转多行建表插入数据方式一方式二 sqlserver一列转多行 建表 CREATE TABLE [dbo].[MM_T_MATER]([fbillno] [NVARCHAR](50) NOT NULL,[fid] [INT] NOT NULL,[FCREATEDATE] [DATETIME] NOT NULL,[FDATE] [DATETIME] NOT NULL,[FPURCHASEORGID] [INT] NOT …

leetcode70_爬楼梯

思路 动态规划 爬到第n阶楼梯的方法数为&#xff1a;第n-1阶楼梯的方法数 第n-2阶楼梯的方法数 func climbStairs(n int) int {if n < 2 {return 1}dp : make([]int, n1)dp[1] 1dp[2] 2for i:3; i<n; i {dp[i] dp[i-1] dp[i-2]}return dp[n] }

C++分析哈希表

目录 哈希表 哈希表介绍 哈希表的数据插入和查找原理 哈希表的存放方法 开散列解决哈希冲突 思路 代码设计 结构设计 数据插入 数据查找 数据删除 闭散列解决哈希冲突 思路 代码设计 结构设计 数据插入 数据查找 数据删除 析构函数设计 比较key相等以及key…

Firefox滚动条在Win10和Win11下表现不一致问题?

文章目录 前言总结解决方法 前言 最近在写页面的时候发现一个非常有意思的事。Firefox滚动条在Win10和Win11下表现居然不一致。在网上几经查找资料&#xff0c; 终于找到原因所在。总结成下面的文章&#xff0c;加深印象也防止下次遇到。 总结 参考文章&#xff1a; Firefox…

淘宝天猫优惠券领取入口直达口令是什么?

词令是一款关键词口令直达工具&#xff1b;打开词令&#xff0c;输入口令「tb88」&#xff0c;搜索直达口令关联的目标淘宝优惠券领取入口。领取成功后&#xff0c;在下单购买默认使用领到的店铺优惠券享受券后价优惠。下面为您准备了图文教程 淘宝优惠券领取入口直达口令是什…

突破视觉界限:单目深度估计算法,智能无人系统的新视角

今天&#xff0c;为大家介绍一项新的SpireCV视觉感知技术——单目深度估计算法&#xff08;MDE, Monocular Depth Estimation&#xff09;。 什么是单目深度估计算法&#xff1f; 简单来说&#xff0c;单目深度估计是指通过单个摄像头获取的图像来估计场景中物体的深度信息。相…

打破老美垄断,潘展乐商业价值起飞

文&#xff5c;琥珀食酒社 作者 | 积溪 奥运会上的潘展乐 真是牛逼坏了 拿下男子100米自由游金牌 打破欧美长达近百年垄断 搞定男子4x100米混合泳金牌 终结了美国在这项目上 10年不败的神话 比赛前 美国选手对他爱答不理 招呼都不打 比赛后美国选手想套热乎 潘展乐…

【鸿蒙开发基础学习】UIAbility 组件启动模式

UIAbility 组件启动模式 UIAbility 的启动模式是指 UIAbility 实例在启动时的不同呈现状态。针对不同的业务场景&#xff0c;系统提供了三种启动模式&#xff1a; singleton&#xff08;单实例模式&#xff09;multiton&#xff08;多实例模式&#xff09;specified&#xff…

WordPress网站克隆:用户指南

在这个数字化时代&#xff0c;拥有自己的网站已经非常普遍了。不管是个人博客还是企业官网&#xff0c;WordPress都提供了便捷的建站方式。但是&#xff0c;有时候我们需要复制一个现有的网站&#xff0c;无论是为了测试新功能还是迁移到新服务器。那么&#xff0c;如何克隆一个…