惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
aimingoo的专栏
aimingoo的专栏
B
Blog RSS Feed
V
Visual Studio Blog
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
博客园 - 【当耐特】
大猫的无限游戏
大猫的无限游戏
Application and Cybersecurity Blog
Application and Cybersecurity Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
The Cloudflare Blog
B
Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Apple Machine Learning Research
Apple Machine Learning Research
M
MIT News - Artificial intelligence
Know Your Adversary
Know Your Adversary
I
InfoQ
T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
C
Cisco Blogs
Spread Privacy
Spread Privacy
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Palo Alto Networks Blog
Simon Willison's Weblog
Simon Willison's Weblog
月光博客
月光博客
博客园 - Franky
Project Zero
Project Zero
G
Google Developers Blog
S
SegmentFault 最新的问题
博客园 - 聂微东
P
Privacy & Cybersecurity Law Blog
The GitHub Blog
The GitHub Blog
阮一峰的网络日志
阮一峰的网络日志
P
Privacy International News Feed
T
Threat Research - Cisco Blogs
S
Schneier on Security
Microsoft Security Blog
Microsoft Security Blog
G
GRAHAM CLULEY
S
Security @ Cisco Blogs
Martin Fowler
Martin Fowler
A
Arctic Wolf
T
Tenable Blog
L
LINUX DO - 最新话题
TaoSecurity Blog
TaoSecurity Blog
Hugging Face - Blog
Hugging Face - Blog
有赞技术团队
有赞技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

博客园 - zhouyu

Vue3手册译稿 - 深入组件 - 插槽 vscode Vue3 多根节点语法检验错误fix Vue3手册译稿 - 深入组件 - 自定义事件 Vue3手册译稿 - 深入组件 - 非prop属性 Vue3手册译稿 - 深入组件 - pros Vue3手册译稿 - 深入组件 - 组件注册 Vue3手册译稿 - 基础 - 组件基础 Vue3手册译稿 - 基础 - 表单输入绑定 Vue3手册译稿 - 基础 - 事件处理 Vue3手册译稿 - 基础 - 列表渲染 Vue3手册译稿 - 基础 - 条件渲染 Vue3手册译稿 - 基础 - Class和Style绑定 Vue3手册译稿 - 基础 - 计算属性及监听器 Vue3手册译稿 - 基础 - Data属性及方法 Vue3手册译稿 - 基础 - 模板语法 Vue3手册译稿 - 基础 - 应用&组件实例 Vue3手册译稿 - 基础 - 介绍 Vue3手册译稿 - 基础 - 安装 元旦三天假期,实现一个电商退单管理系统【四】-手机客户端实现
shardingsphere实现按月分表
zhouyu · 2025-04-04 · via 博客园 - zhouyu

背景

一个老的springboot2的项目,每日订单主表超6万条,从表超10万条,考虑按月分表。调研了shardingsphere和mycat,还顺眼看了下阿里的两个组件。最后决定使用shardingsphere。怪就怪自己太相信大模型,在deepseek和kimi中搜索后,按它们的说法就开干了起来,结果这两个傻货,一顿瞎指挥,浪费了一天时间,每次跟他说不对吧,或者你这样写太不优雅,它总是态度很好的说理解你的需求,其实还是在胡扯。中间无数次想放弃,使用mycat,但又觉得研究到现在,放弃就太可惜了。就放弃了跟大模型的对话,直接到apache官网上找到对应版本的文档写好了。

技术栈

  • springboot
  • mysql8.0
  • shardingsphere 5.3.2
  • jpa 2.2.2

需求描述

主表:tb_erporder,主订单,分片:tb_erporder_yyyyMM

从表:tb_erporder_items,订单明细,分片:tb_erporder_items_yyyyMM

 配置变更

1. shardingsphere独立出一个配置文件,方便维护,跟application一样,分成dev和prd两个

2. application配置文件的datasource要改成从shardingsphere配置文件获取

datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    url: jdbc:shardingsphere:classpath:sharding-dev.yml

3.shardingsphere配置文件

为了配置这个文件,费了老鼻子的劲,一开始按大模型教的,配置键用短横线分隔命名法,实际官方5.x已全部使用驼峰了。其次在配置中如果出现错误,提示非常不友好,他会提示第一行的dataSources无法读取,我以为这行配置问题,改了好多次,大模型一会告诉用datasource,一会是dataSource,一会又是datasources,跟两傻子了样,一个敢教,一个敢学。下面这个错误,其实是因为rules写的不对,我没有注意有一小行:Cannot create property=rules,只看到下面的dataSources

HHH000342: Could not obtain connection to query metadata : Failed to initialize pool: Cannot create property=rules for JavaBean=org.apache.shardingsphere.infra.yaml.config.pojo.YamlRootConfiguration@7f22687e 

in 'reader', line 1, column 1: dataSources:

正确配置如下:

# 数据源集合
dataSources:
  # 数据库1
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://127.0.0.1:3306/orderdb?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    username: root
    password: xxxxxx
rules:
  - !SHARDING
    tables:
      tb_erporder:
        # 真实数据节点,比如数据库源以及数据库在数据库中真实存在的
        actualDataNodes: ds_0.tb_erporder_$->{202501..205012}
        # 分表策略
        tableStrategy:
          # 用于单分片键的标准分片场景
          standard:
            # 分片键
            shardingColumn: send_date
            # 分片算法,对应 rules[0].shardingAlgorithms
            shardingAlgorithmName: tb_erporder-inline
      tb_erporder_items:
        actualDataNodes: ds_0.tb_erporder_items_$->{202501..205012}
        tableStrategy:
          standard:
            shardingColumn: send_date
            shardingAlgorithmName: tb_erporder_items-inline
    # 分片算法
    shardingAlgorithms:
      # 数据表分片算法
      tb_erporder-inline:
        # 根据分片键 分片
        type: INLINE
        # 分片算法
        props:
          algorithm-expression: tb_erporder_$->{new java.text.SimpleDateFormat("yyyyMM").format(send_date)}
      tb_erporder_items-inline:
        type: INLINE
        props:
          algorithm-expression: tb_erporder_items_$->{new java.text.SimpleDateFormat("yyyyMM").format(send_date)}
# 展现逻辑 SQL & 真实 SQL
props:
  sql-show: true

# 20250405更新

分片是成功了,今天做范围查询时,shardingsphere居然把配置表里的202501-205012表全查了一次,我传入的查询日期只是当天数据。。。

于是问大模型有没有办法解决,这次大模型靠谱了点,给了解决方案:自定义切片算法。

先写一个自定义的算法配置类:

/**
 * @author: zhouyu
 * @date: 2025/4/5
 * @Description:
 */
public class MonthRangeShardingAlgorithm implements StandardShardingAlgorithm {
    @Override
    public String doSharding(Collection availableTargetNames, PreciseShardingValue shardingValue) {
        // 精确分片逻辑(单月查询)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        String tableSuffix = sdf.format(shardingValue.getValue());
        String tableName = shardingValue.getLogicTableName() + "_" + tableSuffix;

        // 检查表是否存在
        if (availableTargetNames.contains(tableName)) {
            return tableName;
        }
        throw new IllegalArgumentException("无效的表名: " + tableName);
    }

    @Override
    public Collection<String> doSharding(Collection availableTargetNames, RangeShardingValue shardingValue) {
        // 范围查询分片逻辑
        Set<String> result = new LinkedHashSet<>();

        // 1. 获取查询范围
        Range<Date> range = shardingValue.getValueRange();
        Date lower = range.hasLowerBound() ? range.lowerEndpoint() : null;
        Date upper = range.hasUpperBound() ? range.upperEndpoint() : null;

        // 2. 如果没有范围(全表查询),返回所有可用表(或根据业务限制)
        if (lower == null && upper == null) {
            return availableTargetNames;
        }

        // 3. 计算涉及的月份范围
        Calendar cal = Calendar.getInstance();
        if (lower != null) {
            cal.setTime(lower);
        } else if (upper != null) {
            cal.setTime(upper);
        }

        // 4. 如果是单月查询(不跨月)
        if (isSameMonth(lower, upper)) {
            String tableName = shardingValue.getLogicTableName() + "_" +
                    new SimpleDateFormat("yyyyMM").format(lower != null ? lower : upper);
            if (availableTargetNames.contains(tableName)) {
                result.add(tableName);
            }
            return result;
        }

        // 5. 处理跨月查询
        Calendar current = (Calendar) cal.clone();
        while (upper == null || !current.getTime().after(upper)) {
            String tableName = shardingValue.getLogicTableName() + "_" +
                    new SimpleDateFormat("yyyyMM").format(current.getTime());
            if (availableTargetNames.contains(tableName)) {
                result.add(tableName);
            }

            // 移动到下个月
            current.add(Calendar.MONTH, 1);
            if (upper != null && current.getTime().after(upper)) {
                break;
            }
        }

        return result;
    }
    private boolean isSameMonth(Date d1, Date d2) {
        if (d1 == null || d2 == null) return false;
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(d1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(d2);
        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
    }

再将配置文件的INLINE,修改为BASIC_CLASSED

 # 分片算法
    shardingAlgorithms:
      # 数据表分片算法
      tb_erporder-inline:
        # 根据分片键 Hash 分片
        type: CLASS_BASED
        # 分片数量
        props:
          strategy: standard
          algorithmClassName: com.nantangju.backorder.config.MonthRangeShardingAlgorithm
      tb_erporder_items-inline:
        type: CLASS_BASED
        props:
          strategy: standard
          algorithmClassName: com.nantangju.backorder.config.MonthRangeShardingAlgorithm

写在最后

大模型写代码,现在还没有成熟到可以代替程序员的地步,但相信总有一天会成熟起来,现在的通义灵感,已经可以解决一部分基础问题了,感觉已经可以代替前端工程师了。但是如果没有一定基础,全靠大模型现在还不是时候。

其次是又一次深深的体会到,作为一个技术人员,要对技术充满一定的执着,才能体会到最后成功的喜悦!

5.3.2官网地址:概览 :: ShardingSphere (apache.org)