当前位置: 首页 > article >正文

ruoyi-vue-plus 引入 ShardingSphere-JDBC 实现分库分表

依赖

boot的依赖官方不维护

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc</artifactId>
    <version>5.5.1</version>
</dependency>

需求

我们对 test_demo 表进行分表 test_demo0, test_demo1,根据 id 字段对2取模

数据源配置

application-dev.yml

datasource:
  shardingSphere:
    url: jdbc:shardingsphere:classpath:sharding.yml
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    p6spy: false # 避免冲突

sharding.yml

dataSources:
  shardingmaster:
    dataSourceClassName:  com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://xxxxx/xxx?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
    username: xxxx
    password: xxxxx

sql打印日志框架配置处理

我们配置sharding数据源不开启ps6py,由shardingsphere来处理

props:
  sql-show: true

这样就能实现日志灵活打印了

分表策略配置

rules:
  - !SHARDING
    tables:
      test_demo:
        actualDataNodes: shardingmaster.test_demo$->{0..1}
        tableStrategy:
          standard:
            shardingColumn: id
            shardingAlgorithmName: baomidou_inline
    shardingAlgorithms:
      baomidou_inline:
        type: INLINE
        props:
          algorithm-expression: test_demo$->{id % 2}
          allow-range-query-with-inline-sharding: true
  - !SINGLE
    tables:
      - "*.*"

提一下这里的id还是使用的 mybatisplus 的主键策略

实现代码

建表sql

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for test_demo
-- ----------------------------
DROP TABLE IF EXISTS `test_demo0`;
CREATE TABLE `test_demo0`  (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `tenant_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '000000' COMMENT '租户编号',
  `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门id',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id',
  `order_num` int(11) NULL DEFAULT 0 COMMENT '排序号',
  `test_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'key键',
  `value` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '值',
  `version` int(11) NULL DEFAULT 0 COMMENT '版本',
  `create_dept` bigint(20) NULL DEFAULT NULL COMMENT '创建部门',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人',
  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
  `update_by` bigint(20) NULL DEFAULT NULL COMMENT '更新人',
  `del_flag` int(11) NULL DEFAULT 0 COMMENT '删除标志',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '测试单表' ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS `test_demo1`;
CREATE TABLE `test_demo1`  (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `tenant_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '000000' COMMENT '租户编号',
  `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门id',
  `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id',
  `order_num` int(11) NULL DEFAULT 0 COMMENT '排序号',
  `test_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'key键',
  `value` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '值',
  `version` int(11) NULL DEFAULT 0 COMMENT '版本',
  `create_dept` bigint(20) NULL DEFAULT NULL COMMENT '创建部门',
  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
  `create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人',
  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
  `update_by` bigint(20) NULL DEFAULT NULL COMMENT '更新人',
  `del_flag` int(11) NULL DEFAULT 0 COMMENT '删除标志',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '测试单表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

实体类我们不做修改

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_demo")
public class TestDemo extends TenantEntity {

    @Serial
    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id")
    private Long id;

    /**
     * 部门id
     */
    private Long deptId;

    /**
     * 用户id
     */
    private Long userId;

    /**
     * 排序号
     */
    @OrderBy(asc = false, sort = 1)
    private Integer orderNum;

    /**
     * key键
     */
    private String testKey;

    /**
     * 值
     */
    private String value;

    /**
     * 版本
     */
    @Version
    private Long version;

    /**
     * 删除标志
     */
    @TableLogic
    private Long delFlag;

}
List<TestDemo> queryListSharding(TestDemoBo bo);
Boolean insertByBoSharding(TestDemoBo bo);

@Override
@DS("shardingSphere")
public List<TestDemo> queryListSharding(TestDemoBo bo) {
    return baseMapper.selectList(buildQueryWrapper(bo));
}

@Override
@DS("shardingSphere")
public Boolean insertByBoSharding(TestDemoBo bo) {
    TestDemo add = MapstructUtils.convert(bo, TestDemo.class);
    validEntityBeforeSave(add);
    boolean flag = baseMapper.insert(add) > 0;
    if (flag) {
        bo.setId(add.getId());
    }
    return flag;
}

private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
    Map<String, Object> params = bo.getParams();
    LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
// 添加对 id 的查询
    lqw.eq(ObjectUtil.isNotNull(bo.getId()), TestDemo::getId, bo.getId());
    lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
    lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
    lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
        TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
    lqw.orderByAsc(TestDemo::getId);
    return lqw;
}

@RequiredArgsConstructor
@RestController
@RequestMapping("/demo/sharding")
public class TestDemoShardingController  extends BaseController {

    private final ITestDemoService testDemoService;

    /**
     * 查询测试单表列表
     */
    @SaCheckPermission("demo:demo:list")
    @GetMapping("/list")
    public List<TestDemo> list(TestDemoBo bo) {
        return testDemoService.queryListSharding(bo);
    }

    /**
     * 新增测试单表
     */
    @SaCheckPermission("demo:demo:add")
    @PostMapping()
    public R<Void> add(@RequestBody TestDemoBo bo) {
        return toAjax(testDemoService.insertByBoSharding(bo));
    }
}

我们对需要分库分表的方法手动指定 sharding 的数据源即可实现执行分库分表的策略

测试

postman

测试新增

可以看到会被路由到不同的表上

测试全量查询

会去所有分表上去搜索

测试根据id查询

会按照id sharding策略去搜索指定的表

shardingsphere-proxy引入方便dba运维

修改 config-sharding.yaml

schemaName: sharding_db

dataSources:
  ds_remote:
    url: jdbc:mysql://xxx:xxx/xxx?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
    username: root
    password: xxxx

rules:
- !SHARDING
  tables:
    test_demo:
      actualDataNodes: ds_remote.test_demo$->{0..1}
      tableStrategy:
        standard:
          shardingColumn: id
          shardingAlgorithmName: alg_inline_demo_id  
  shardingAlgorithms:
    alg_inline_demo_id:
      type: INLINE
      props:
        algorithm-expression: test_demo$->{id % 2}

可以直接查出来

补充

绑定表

eg,订单的主子表,都需要分片,主表和子表分片的规则和字段需要相同,比如都根据order_id字段

SELECT
	i.* 
FROM
	t_order o
	JOIN t_order_item i ON o.order_id = i.order_id 
WHERE
	o.order_id IN ( 10, 11 );

可以减少关联子表sql执行的数量->路由只会使用主表的路由

SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
-> 
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
bindingTables:
  - t_order,t_order_item

广播表

通常是字典表->所有分片中维护相同的副本

broadcastTables:
  - t_dict

http://www.kler.cn/a/516252.html

相关文章:

  • 服务器安装ESXI7.0系统及通过离线包方式升级到ESXI8.0
  • 微服务学习-Nacos 注册中心实战
  • 软件测试 —— 性能测试(jmeter)
  • 99.6 金融难点通俗解释:股息率(DV)
  • 联想电脑怎么用u盘装系统_联想电脑用u盘装win10系统教程
  • 【2024年 CSDN博客之星】我的2024年创作之旅:从C语言到人工智能,个人成长与突破的全景回顾
  • docker 部署.netcore应用优势在什么地方?
  • Linux下Ubuntun系统报错find_package(BLAS REQUIRED)找不到
  • 华为OD机试E卷 --树状结构查询--24年OD统一考试(Java JS Python C C++)
  • 概率密度函数(PDF)分布函数(CDF)——直方图累积直方图——直方图规定化的数学基础
  • 智源研究院与乐聚机器人成立具身智能联合实验室
  • 深度学习实战图像OCR识别
  • 【博客之星】2024年度创作成长总结 - 面朝大海 ,春暖花开!
  • STM32——LCD
  • Spring Boot中选择性加载Bean的几种方式
  • 如何使用 Node.js 构建一个简单的 API?
  • Python语言的安全开发
  • 把 PVE 下的机械硬盘(非SSD系统盘)分配给虚拟机使用
  • 打破常规,Linux内核新的数据结构上场maple tree
  • 苍穹外卖—订单模块
  • 由于请求的竞态问题,前端仔喜提了一个bug
  • idea修改模块名导致程序编译出错
  • 【全栈】SprintBoot+vue3迷你商城(3)
  • 谷粒商城——商品服务-三级分类
  • 无界云剪音频教程:提升视频质感
  • 【游戏设计原理】79 - 可变奖励