分库分表与自定义分表规则

总体介绍

  • Oinone的分库分表方案是基于Sharding-JDBC的整合方案,要先具备一些Sharding-JDBC的知识。[Sharding-JDBC]https://shardingsphere.apache.org/document/current/cn/overview/

  • 做分库分表前,大家要有一个明确注意的点就是分表字段(也叫均衡字段)的选择,它是非常重要的,与业务场景非常相关。在明确了分库分表字段以后,甚至在功能上都要做一些妥协。比如分库分表字段在查询管理中做为查询条件是必须带上的,不然效率只会更低。

  • 分表字段不允许更新,所以代码里更新策略设置类永不更新,并在设置了在页面修改的时候为readonly

配置分表策略

  1. 配置ShardingModel模型走分库分表的数据源pamirsSharding
  2. 为pamirsSharding配置数据源以及sharding规则
    a. pamirs.sharding.define用于oinone的数据库表创建用
    b. pamirs.sharding.rule用于分表规则配置
  3. 为pamirsSharding配置数据源以及sharding规则

    1)指定模型对应数据源

pamirs:
  framework:
    system:
      system-ds-key: base
      system-models:
        - base.WorkerNode
    data:
      default-ds-key: pamirs
      ds-map:
        base: base
      modelDsMap:
        "[demo.ShardingModel]": pamirsSharding  #配置模型对应的库

2)分库分表规则配置

pamirs: 
  sharding:
    define:
      data-sources:
        ds: pamirs
        pamirsSharding: pamirs #申明pamirsSharding库对应的pamirs数据源
      models:
        "[trigger.PamirsSchedule]":
          tables: 0..13
        "[demo.ShardingModel]":
          tables: 0..7
          table-separator: _
    rule:
      pamirsSharding: #配置pamirsSharding库的分库分表规则
        actual-ds:
          - pamirs  #申明pamirsSharding库对应的pamirs数据源
        sharding-rules:
          # Configure sharding rule ,以下配置跟sharding-jdbc配置一致
          - tables:
              demo_core_sharding_model: #demo_core_sharding_model表规则配置
                actualDataNodes: pamirs.demo_core_sharding_model_${0..7}
                tableStrategy:
                  standard:
                    shardingColumn: user_id
                    shardingAlgorithmName: table_inline
            shardingAlgorithms:
              table_inline:
                type: INLINE
                props:
                  algorithm-expression: demo_core_sharding_model_${(Long.valueOf(user_id) % 8)}
        props:
          sql.show: true

自定义规则

  • 默认规则即通用的分库分表策略,如按照数据量、哈希等方式进行分库分表;通常默认规则是可以的。
  • 但在一些复杂的业务场景下,使用默认规则可能无法满足需求,需要根据实际情况进行自定义。例如,某些业务可能有特定的数据分布模式或者查询特点,需要定制化的分库分表规则来优化数据访问性能或者满足业务需求。在这种情况下,使用自定义规则可以更好地适应业务的需求。

自定义分表规则示例

示例1:按月份分表(DATE_MONTH )

package pro.shushi.pamirs.demo.core.sharding;

import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Range;
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 pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;

import java.util.*;

/**
 * @author wangxian
 * @version 1.0
 * @description
 */
@Component
@Slf4j
public class DateMonthShardingAlgorithm implements StandardShardingAlgorithm<Date> {

    private Properties props;

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> preciseShardingValue) {
        Date date = preciseShardingValue.getValue();
        String suffix = "_" + (DateUtil.month(date) + 1);
        for (String tableName : availableTargetNames) {
            if (tableName.endsWith(suffix)) {
                return tableName;
            }
        }
        throw new IllegalArgumentException("未找到匹配的数据表");
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> rangeShardingValue) {
        List<String> list = new ArrayList<>();
        log.info(rangeShardingValue.toString());
        Range<Date> valueRange = rangeShardingValue.getValueRange();
        Date lowerDate = valueRange.lowerEndpoint();
        Date upperDate = valueRange.upperEndpoint();
        Integer begin = DateUtil.month(lowerDate) + 1;
        Integer end = DateUtil.month(upperDate) + 1;
        TreeSet<String> suffixList = ShardingUtils.getSuffixListForRange(begin, end);
        for (String tableName : availableTargetNames) {
            if (containTableName(suffixList, tableName)) {
                list.add(tableName);
            }
        }
        return list;
    }

    private boolean containTableName(Set<String> suffixList, String tableName) {
        boolean flag = false;
        for (String s : suffixList) {
            if (tableName.endsWith(s)) {
                flag = true;
                break;
            }
        }
        return flag;
    }

    @Override
    public void init() {

    }

    @Override
    public String getType() {
        return "DATE_MONTH";
    }

    @Override
    public Properties getProps() {
        return this.props;
    }

    @Override
    public void setProps(Properties properties) {
        this.props = props;
    }
}

示例2:按特定字段截取去取模分表

package pro.shushi.pamirs.demo.core.sharding;

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 pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;

import java.util.Collection;
import java.util.Properties;

/**
 * @author wangxian
 * @version 1.0
 * @description
 */
@Component
@Slf4j
public class AppUserCodeShardingAlgorithm implements StandardShardingAlgorithm<String> {

    private Properties props;

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> preciseShardingValue) {
        String appUserCode = preciseShardingValue.getValue();
        String suffix = "_" + Long.parseLong(appUserCode.substring(1)) % 21;
        for (String tableName : availableTargetNames) {
            if (tableName.endsWith(suffix)) {
                return tableName;
            }
        }
        throw new IllegalArgumentException("未找到匹配的数据表");
    }

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

    @Override
    public String getType() {
        return "APP_USER_CODE_TYPE";
    }

    @Override
    public Properties getProps() {
        return this.props;
    }

    @Override
    public void setProps(Properties properties) {
        this.props = props;
    }

    @Override
    public void init() {

    }
}

使用自定义分表策略

1)指定模型对应数据源

pamirs:
  framework:
    system:
      system-ds-key: base
      system-models:
        - base.WorkerNode
    data:
      default-ds-key: pamirs_biz
      ds-map:
        base: base
        demo_core: pamirs
      modelDsMap:
        "[demo.record.MsgRecode]": pamirsSharding

2)分库分表规则配置

pamirs:
  sharding:
    define:
      data-sources:
        ds: pamirs
        pamirsSharding: pamirs
      models:
        "[trigger.PamirsSchedule]":
          tables: 0..13
        "[demo.record.MsgRecode]":
          tables: 0..20
          table-separator: _
    rule:
      pamirsSharding:
        actual-ds:
          - pamirs
        sharding-rules:
          - tables:
              demo_core_record_msg_recode:
                actualDataNodes: pamirs.demo_core_record_msg_recode_${0..20}
                tableStrategy:
                  standard:
                    shardingColumn: app_user_code
                    shardingAlgorithmName: app_user_code_table_algorithm
            shardingAlgorithms:
              app_user_code_table_algorithm:
                type: APP_USER_CODE_TYPE
                props:
                  strategy: STANDARD
                  algorithmClassName:
                    pro.shushi.pamirs.demo.core.sharding.AppUserCodeShardingAlgorithm

配置自定义规则SPI

分库分表规则SPI

在resources/META-INF/services 配置 org.apache.shardingsphere.sharding.spi.ShardingAlgorithm

pro.shushi.pamirs.demo.core.sharding.AppUserCodeShardingAlgorithm
pro.shushi.pamirs.demo.core.sharding.DateMonthShardingAlgorithm

Oinone社区 作者:望闲原创文章,如若转载,请注明出处:https://doc.oinone.top/backend/7155.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
望闲的头像望闲数式管理员
上一篇 2024年5月9日 pm3:56
下一篇 2024年5月13日 pm7:06

相关推荐

  • 项目中工作流引入和流程触发

    目录 1. 使用工作流需要依赖的包和设置2. 触发方式2.1 自动触发方式2.2 触发方式 1.使用工作流需要依赖的包和设置 1.1 工作流需要依赖的模块 需在pom.xml中增加workflow、sql-record和trigger相关模块的依赖 workflow:工作流运行核心模块 sql-record:监听流程发布以后对应模型的增删改监听 trigger:异步任务调度模块 <dependency> <groupId>pro.shushi.pamirs.workflow</groupId> <artifactId>pamirs-workflow-api</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.workflow</groupId> <artifactId>pamirs-workflow-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-sql-record-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-core</artifactId> </dependency> <dependency> <groupId>pro.shushi.pamirs.core</groupId> <artifactId>pamirs-trigger-bridge-tbschedule</artifactId> </dependency> 在application.yml中增加对应模块的依赖以及sql-record路径以及其他相关设置 pamirs: … record: sql: #改成自己路径 store: /opt/pamirs/logs … boot: init: true sync: true modules: … – sql_record – trigger – workflow … sharding: define: data-sources: ds: pamirs models: "[trigger.PamirsSchedule]": tables: 0..13 event: enabled: true schedule: enabled: true # ownSign区分不同应用 ownSign: demo rocket-mq: # enabled 为 false情况不用配置 namesrv-addr: 192.168.6.2:19876 trigger: auto-trigger: true 2.触发方式 2.1自动触发方式 在流程设计器中设置触发方式,如果设置了代码触发方式则不会自动触发 2.2代码调用方式触发 2.2.1.再流程设计器中触发设置中,设置为是否人工触发设置为是 2.2.2.查询数据库获取该流程的编码 2.2.3.在代码中调用 /** * 触发⼯作流实例 */ private Boolean startWorkflow(WorkflowD workflowD, IdModel modelData) { WorkflowDefinition workflowDefinition = new WorkflowDefinition().queryOneByWrapper( Pops.<WorkflowDefinition>lambdaQuery() .from(WorkflowDefinition.MODEL_MODEL) .eq(WorkflowDefinition::getWorkflowCode, workflowD.getCode()) .eq(WorkflowDefinition::getActive, 1) ); if (null == workflowDefinition) { // 流程没有运⾏实例 return Boolean.FALSE; } String model = Models.api().getModel(modelData); //⼯作流上下⽂ WorkflowDataContext wdc = new WorkflowDataContext(); wdc.setDataType(WorkflowVariationTypeEnum.ADD); wdc.setModel(model); wdc.setWorkflowDefinitionDefinition(workflowDefinition.parseContent()); wdc.setWorkflowDefinition(workflowDefinition); wdc.setWorkflowDefinitionId(workflowDefinition.getId()); IdModel copyData = KryoUtils.get().copy(modelData); // ⼿动触发创建的动作流,将操作⼈设置为当前⽤户,作为流程的发起⼈ copyData.setCreateUid(PamirsSession.getUserId()); copyData.setWriteUid(PamirsSession.getUserId()); String jsonData = JsonUtils.toJSONString(copyData.get_d()); //触发⼯作流 新增时触发-onCreateManual 更新时触发-onUpdateManual Fun.run(WorkflowModelTriggerFunction.FUN_NAMESPACE, "onCreateManual", wdc, msgId, jsonData); return Boolean.TRUE; }

    2023年11月7日
    1.7K00
  • 如何把平台功能菜单加到项目中?

    概述 在使用Oinone低代码平台进行项目开发的过程中,会存在把平台默认提供的菜单加到自己的项目中。这篇文章介绍实现方式,以角色管理为例。 1. 低代码情况 即项目是通过后端代码初始化菜单的方式。 通常在 XXXMenu.java类通过@UxMenu注解的方式,代码片段如下: 此种情况与添加项目本地的菜单无区别,具体代码: @UxMenu(value = "账号管理", icon = "icon-yonghuguanli") class AccountManage { @UxMenu("用户管理") @UxRoute(value = CustomerCompanyUserProxy.MODEL_MODEL, title = "用户管理") class CompanyUserManage { } @UxMenu("角色管理") @UxRoute(value = AuthRole.MODEL_MODEL, module = AdminModule.MODULE_MODULE, title = "角色管理") class RoleManage { } @UxMenu("操作日志") @UxRoute(value = OperationLog.MODEL_MODEL, module = AdminModule.MODULE_MODULE/***菜单所挂载的模块**/) class OperateLog { } } 2. 无代码情况 在界面设计器中,新建菜单–>选择绑定已有页面,进行发布即可。

    2024年4月19日
    1.8K00
  • 工作流用户待办过滤站内信

    工作流用户待办过滤站内信 全局过滤 启动工程application.yml中配置: pamirs: workflow: notify: false 个性化过滤 实现pro.shushi.pamirs.workflow.app.api.service.WorkflowMailFilterApi接口 返回true表示需要发送站内信 返回false表示不需要发送站内信 示例: import org.apache.commons.lang3.StringUtils; import pro.shushi.pamirs.message.model.PamirsMessage; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.workflow.app.api.model.WorkflowUserTask; import pro.shushi.pamirs.workflow.app.api.service.WorkflowMailFilterApi; /** * MyWorkflowMailFilterImpl * * @author yakir on 2025/02/24 16:28. */ @Fun(WorkflowMailFilterApi.FUN_NAMESPACE) public class MyWorkflowMailFilterImpl implements WorkflowMailFilterApi { @Override @Function public Boolean filter(WorkflowUserTask workflowUserTask, PamirsUser user, PamirsMessage message) { // 按用户待办过滤 workflowUserTask if (10000L == workflowUserTask.getInitiatorUid()){ return true; } // 按用户过滤 user if (1000L == user.getId()){ return true; } // 按站内信消息过滤 message if (StringUtils.contains(message.getBody(), "你好")) { return true; } return false; } }

    2025年2月24日
    1.1K00
  • 元数据表介绍

    模型 模型元数据的讲解 https://doc.oinone.top/oio4/9281.html base_model 模型表 字段名 备注 示例 system_source BASE是系统创建, MANUAL是人工创建 MANUAL pk 主键 id module 模块编码 demo_core model 模型编码 demo.PetType name api名称 petType lname 模型代码名称 pro.shushi.pamirs.demo.api.model.PetType table 逻辑数据表名称 demo_core_pet_type ds_key 逻辑数据源名 pamirs type 模型类型 store display_name 显示名称 品种 data_manager 是否允许系统根据模型变化自动创建表和更新表 1 ordering 排序 createDate DESC, id DESC super_models 父模型 demo.AbstractDemoIdModel uniques 唯一索引 indexes 索引 name,createDate 模块 模块元数据的讲解 https://doc.oinone.top/oio4/9279.html base_module 模块表 字段名 备注 示例 display_name 显示名称 OinoneDemo name api名称 DemoCore module 模块编码 demo_core module_dependencies 依赖模块编码列表 base,common,file,trigger module_exclusions 互斥模块编码列表 module_upstreams 上游模块编码列表 system_source BASE是系统创建, MANUAL是人工创建 MANUAL web web应用 1 default_home_page_model 默认主页模型编码 函数 函数元数据的讲解 https://doc.oinone.top/oio4/9282.html base_function 函数表 字段名 备注 示例 display_name 显示名称 根据条件分页查询记录列表和总数 clazz 函数位置 pro.shushi.pamirs.framework.orm.DefaultReadApi module 模块 demo_core method 函数方法 queryPage namespace 函数命名空间 demo.PetType argument_list 函数参数 [{"ltype":"pro.shushi.pamirs.meta.api.dto.condition.Pagination","model":"base.Pagination","modelGeneric":false,"multi":false,"name":"page","ttype":"m2o"},{"ltype":"pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper","ltypeT":"java.lang.Object","model":"base.Condition","modelGeneric":true,"multi":false,"name":"queryWrapper","ttype":"m2o"}] fun 函数编码 queryPage return_type 返回值类型 {"ltype":"pro.shushi.pamirs.meta.api.dto.condition.Pagination","model":"base.Pagination","modelGeneric":false,"multi":false,"ttype":"m2o"} sys 由系统产生的元数据 1 type 函数类型 1: CREATE, 2: DELETE, 4: UPDATE, 8: QUERY 8 data_manager 数据管理器函数 1 codes 代码内容 open_level 开放级别 2: LOCAL, 4: REMOTE, 8: API, 6: LOCAL+REMOTE, 10: LOCAL+API, 12: REMOTE+API, 14:LOCAL+REMOTE+API 14 模型字段 字段讲解 https://doc.oinone.top/oio4/9239.html base_field 字段表 字段名 备注 示例 system_source BASE是系统创建, MANUAL是人工创建 MANUAL name api名称 name field 字段编码 name ttype 关系类型, 类型:m2o/o2m/m2m/enum/string/integer/map/datetime/related/money/html string model 模型编码…

    2024年8月23日
    1.2K00
  • 【OpenGauss】后端部署使用OpenGauss高斯数据库

    Gauss数据库配置 适配版本 4.7.8.3之后的版本 配置步骤 Maven配置 去华为官网下周驱动包:gsjdbc4.jar;https://support.huaweicloud.com/mgtg-dws/dws_01_0032.html <dependency> <groupId>org.postgresql</groupId> <artifactId>gsjdbc</artifactId> <version>4</version> <scope>system</scope> <!– 下面两种方式都可以–> <systemPath>${pom.basedir}/libs/gsjdbc4.jar</systemPath> <!–<systemPath>/Users/wangxian/java-tools/guassdb/gsjdbc4.jar</systemPath>–> </dependency> 导入 scope 为 system 的包,spring 编译插件需要增加 includeSystemScope: true 配置。 <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <includeSystemScope>true</includeSystemScope> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> JDBC连接配置 pamirs: datasource: pamirs: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:5432/pamirs?currentSchema=demo username: XXXXXX password: XXXXXX initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: org.postgresql.Driver url: jdbc:postgresql://127.0.0.1:5432/pamirs?currentSchema=demo_base username: XXXXXX password: XXXXXX initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true 连接url配置 点击查看官方文档:官方文档 url格式 jdbc:postgresql://${host}:${port}/${database}?currentSchema=${schema} 在pamirs连接配置时,${database}和${schema}必须完整配置,不可缺省。 其他连接参数如需配置,可自行查阅相关资料进行调优。 方言配置 pamirs方言配置 pamirs: dialect: ds: base: type: GaussDB version: 5 majorVersion: 5.0.1 pamirs: type: GaussDB version: 5 majorVersion: 5.0.1 数据库版本 type version majorVersion 5.x GaussDB 5 5.0.1 PS:由于方言开发环境为5.0.1版本,其他类似版本(5.x)原则上不会出现太大差异,如出现其他版本无法正常支持的,可在文档下方留言。 schedule方言配置 pamirs: event: enabled: true schedule: enabled: true dialect: type: GaussDB version: 5 major-version: 5.0.1 type version majorVersion GaussDB 5 5.0.1 PS:由于schedule的方言在多个版本中并无明显差异,目前仅提供一种方言配置。 其他配置 逻辑删除的值配置 pamirs: mapper: global: table-info: logic-delete-value: (EXTRACT(epoch FROM CURRENT_TIMESTAMP) * 1000000 + EXTRACT(MICROSECONDS FROM CURRENT_TIMESTAMP))::bigint Gauss数据库用户初始化及授权 — init root…

    2024年3月27日
    2.4K00

Leave a Reply

登录后才能评论