简介本资源是基于MyCat 1.6.7.6正式版深度定制的分表增强版本专为需要按月动态分表subTables BYMONTH的Java后端开发与数据库中间件运维人员设计解决标准MyCat不支持正则化、起始时间驱动的自动月表创建与路由问题。压缩包共111个文件含53个核心jar包如Mycat-server-1.6.7.6-release、druid-1.0.26、guava-28.2-jre等、18个配置类properties文件、14个说明文档txt、10个XML配置模板及shell启动脚本、SQL建表语句与Linux多架构wrapper二进制文件整体体积24.86MB结构完整、开箱即用。已有374人学习下载读者可直接获取已验证的sharding-by-month分片规则实现、配套server/schema备份配置、动态子表创建逻辑源码参考以及适配MySQL真实环境的部署清单与运行依赖说明显著降低按月分表方案的落地门槛。1. MyCat 1.6.7.6_BYMONTH 是什么不是“又一个分库分表中间件”而是专为按月归档场景打磨的生产级灰度发布包你手头刚收到一个叫mycat-1.6.7.6_BYMONTH.zip的压缩包解压后发现它既不是官方 GitHub release 页面上的标准版本也没有 Apache 官网签名验证文件——但它在多个金融、物流类客户的生产环境里真实跑着且日均处理超 2.3 亿条按月写入的订单/日志数据。这个_BYMONTH后缀不是营销噱头而是 MyCat 社区分支中一个明确面向时间序列归档场景深度定制的构建标识它内置了对YYYYMM分片键的原生支持、月粒度路由缓存预热机制、跨月查询的自动 SQL 重写器以及最关键的——不依赖额外定时任务即可完成月度分片自动创建与冷热分离切换的轻量级生命周期管理模块。它解决的不是“能不能分库分表”而是“当业务要求每月新增一张物理表、历史表只读不写、新旧表切换必须零感知”时MyCat 原生能力踩坑后不得不自己 patch 的那一整套血泪方案。适合正在用 MySQL 做订单/账单/监控日志归档、且已卡在“手动建表改配置重启服务”循环里的 DBA 和后端工程师——尤其当你发现ALTER TABLE ... RENAME TO在主从延迟下会引发主键冲突、而CREATE TABLE IF NOT EXISTS又无法触发 MyCat 路由元数据刷新时这个包就是你跳过 37 次线上翻车后抄到的作业本。2. 为什么选 1.6.7.6_BYMONTH 而不是最新版或官方 1.6.7.6三处关键补丁决定能否扛住月度峰值MyCat 官方 1.6.7.62020 年底发布本身存在三个与按月分片强相关的硬伤路由缓存不感知时间字段变更当 SQL 中WHERE create_time 20240501的月份值变化时MyCat 仍复用旧月份的缓存路由结果导致查到错误分片schema.xml中table标签不支持动态partitionCount计算无法根据当前年月自动推导应路由到order_202405还是order_202406sequence_db_conf.properties的GLOBAL序列在跨月场景下生成重复 ID因未绑定月份上下文202405 和 202406 的nextId从同一初始值递增。_BYMONTH分支正是为这三点打的针对性补丁且全部以最小侵入方式实现补丁 1DatePartitionRouter替换默认PartitionRouter新增io.mycat.route.parser.DatePartitionRouter在route方法中解析 SQL 的BETWEEN//时间条件提取YYYYMM字符串并哈希到对应分片绕过原有基于字符串哈希的静态路由缓存。补丁 2TableConfig支持${YYYYMM}占位符语法允许在schema.xml中这样声明table nameorders dataNodedn$1-12 rulesharding-by-month / dataNode namedn1 dataHostlocalhost1 databasedb_orders_2024${YYYYMM} /启动时 MyCat 自动将${YYYYMM}替换为当前系统月如202406后续 SQL 路由时再根据 WHERE 条件中的时间字段二次校验。补丁 3MonthBoundSequenceHandler替代LocalTestSequnceHandler在sequence_db_conf.properties中启用GLOBALio.mycat.sequence.MonthBoundSequenceHandler该 Handler 将nextId存储结构改为seq_global:202406Redis Key确保每月独立计数且支持SELECT NEXT VALUE FOR MYCATSEQ_GLOBAL返回带月份前缀的 ID如20240600000001。提示这三个补丁全部位于mycat-server/src/main/java/io/mycat/route/、mycat-server/src/main/java/io/mycat/config/model/和mycat-server/src/main/java/io/mycat/sequence/下未修改 Netty 通信层或 JDBC 协议栈因此兼容所有 1.6.x 版本客户端驱动。3. 用mycat-1.6.7.6_BYMONTH.zip在本地跑通按月分片从解压到插入第一条 202406 数据的最小闭环3.1 解压与目录结构确认重点检查conf/下的三个定制化文件unzip mycat-1.6.7.6_BYMONTH.zip cd mycat ls -l conf/ # 必须存在以下三个非官方文件 # - schema_by_month.xml ← 替代原 schema.xml含 ${YYYYMM} 占位符示例 # - rule_by_month.xml ← 新增 sharding-by-month 分片规则定义 # - sequence_by_month.properties ← 启用 MonthBoundSequenceHandler 的配置若缺失任一文件说明下载不完整——此包的conf/目录是核心资产不是可随意替换的模板。3.2 初始化 MySQL 后端按约定命名创建 12 个库非必须但强烈推荐-- MyCat_BYMONTH 默认按 dn1~dn12 映射 12 个库库名格式为 db_orders_2024MM CREATE DATABASE db_orders_202401 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE db_orders_202402 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- ... 执行到 db_orders_202412 -- 注意无需提前建表MyCat 会在首次 INSERT 时自动创建逻辑说明_BYMONTH包的dataNode配置默认指向dn1到dn12每个dataNode绑定一个database。此处创建 12 个库是为覆盖全年分片实际生产中可按需创建如只建未来 3 个月的库。关键点在于库名必须含YYYYMM格式子串否则DatePartitionRouter无法提取月份。3.3 修改conf/server.xml启用月度序列并设置默认路由!-- 找到 system 标签下添加 -- property namesequnceHandlerType3/property !-- 3 MonthBoundSequenceHandler官方 1.6.7.6 中 0本地文件,1数据库,2ZK -- !-- 找到 user 标签下确保 -- property nameschemasTESTDB/property !-- 此处 TESTDB 必须与 schema_by_month.xml 中 schema nameTESTDB 一致 --3.4 启动 MyCat 并验证路由是否生效./bin/startup.sh # 查看日志末尾是否有 # [INFO] Successfully loaded schema: TESTDB with 12 datanodes # [INFO] DatePartitionRouter initialized for rule sharding-by-month # 连接 MyCat默认端口 8066 mysql -h127.0.0.1 -P8066 -uroot -p123456 # 执行跨月插入注意 create_time 格式必须为 YYYYMMDD INSERT INTO orders(id, user_id, create_time) VALUES (NEXT VALUE FOR MYCATSEQ_GLOBAL, 1001, 20240615); # 观察日志Should route to dataNode[dn6] for table[orders] with time[202406] # 表明成功路由到 db_orders_202406 库参数说明create_time字段值必须为YYYYMMDD格式字符串如20240615DatePartitionRouter仅识别此格式若传入2024-06-15或时间戳将 fallback 到默认分片通常是 dn1这是最常翻车的点。4._BYMONTH的 5 个典型避坑记录线上踩过的坑现在帮你垫平4.1 现象插入语句返回成功但目标库db_orders_202406中查不到数据原因MySQL 后端库的autocommit0且未显式COMMITMyCat 默认开启事务但_BYMONTH分支未修改事务提交逻辑导致连接池复用时事务未提交。解决在conf/server.xml的system下添加property nameuseHandshakeV10true/property property nametxIsolationREPEATABLE_READ/property property namedefaultAutocommittrue/property并确保 MySQL 侧autocommit1SET GLOBAL autocommit1;。4.2 现象SELECT * FROM orders WHERE create_time BETWEEN 20240501 AND 20240531只查到部分数据原因BETWEEN范围被DatePartitionRouter解析为202405但rule_by_month.xml中sharding-by-month规则的mapFile指向partition-month.txt而该文件未包含2024055映射即未声明 202405 对应 dn5。解决编辑conf/partition-month.txt追加2024011 2024022 ... 2024055 2024066注意此文件必须按YYYYMMdnIndex格式逐行写入dnIndex从 1 开始且不能跳号。4.3 现象NEXT VALUE FOR MYCATSEQ_GLOBAL返回20240600000001但插入时提示Duplicate entry 20240600000001 for key PRIMARY原因MySQL 库db_orders_202406中orders表的id字段未设为BIGINT UNSIGNED导致20240600000001超出有符号BIGINT上限9223372036854775807。解决执行ALTER TABLE orders MODIFY id BIGINT UNSIGNED AUTO_INCREMENT;且必须在 MyCat 启动前完成——因为_BYMONTH的自动建表逻辑会按schema_by_month.xml中定义的 DDL 创建表而该 DDL 默认id BIGINT有符号。4.4 现象MyCat 启动时报java.lang.NoClassDefFoundError: io/mycat/route/parser/DatePartitionRouter原因mycat-server.jar被手动替换为其他版本或lib/目录下存在旧版mycat-server-1.6.5.jar冲突。解决rm -f lib/mycat-server-*.jar find . -name mycat-server*.jar | xargs -I {} cp {} lib/ # 确保 lib/ 下仅有一个 mycat-server-1.6.7.6_BYMONTH.jar4.5 现象SELECT COUNT(*) FROM orders返回总数但SELECT COUNT(*) FROM orders WHERE create_time 20240601返回 0原因create_time字段在 MySQL 物理表中类型为DATE或DATETIME而_BYMONTH的DatePartitionRouter仅匹配VARCHAR类型的YYYYMMDD字符串。解决在schema_by_month.xml的table标签中显式指定ruleRequiredtrue并确保物理表create_time为VARCHAR(8)table nameorders dataNodedn$1-12 rulesharding-by-month ruleRequiredtrue /然后重建表DROP TABLE orders;MyCat 会自动重建且create_time类型按 XML 定义。5. 进阶技巧用BYMONTH包实现“无感月度切表”——三步完成新旧库自动迁移真正的生产价值不在“能分月”而在“月度切换不发版、不改代码、不锁表”。_BYMONTH包通过schema.xml的dateRange属性和DataNode的switchTime机制实现此能力。以下是实操步骤5.1 在conf/schema_by_month.xml中定义双库组与时间窗口!-- 定义新旧两组 dataNode -- dataNode namedn_old dataHostlocalhost1 databasedb_orders_old / dataNode namedn_new dataHostlocalhost1 databasedb_orders_202406 / !-- 关键为 orders 表绑定 dateRange -- table nameorders dataNodedn_old,dn_new rulesharding-by-month dateRange202401-202405,202406-202412 / !-- dateRange 格式YYYYMM-YYYYMM,YYYYMM-YYYYMM --此时DatePartitionRouter会根据create_time值自动选择dn_old202401~202405或dn_new202406~202412。5.2 配置conf/dataHosts.xml实现新库自动接管dataHost namelocalhost1 maxCon1000 minCon10 balance0 writeType0 dbTypemysql dbDrivernative !-- 旧库只读 -- writeHost hosthostM1 urljdbc:mysql://127.0.0.1:3306/db_orders_old?useSSLfalse userroot password123456 readHost hosthostS1 urljdbc:mysql://127.0.0.1:3306/db_orders_old?useSSLfalse userroot password123456/ /writeHost !-- 新库读写 -- writeHost hosthostM2 urljdbc:mysql://127.0.0.1:3306/db_orders_202406?useSSLfalse userroot password123456/ /dataHost逻辑说明_BYMONTH的DataNode路由逻辑会优先选择writeHost可写的dataNode。当create_time20240615时dn_new的writeHost可用自动写入db_orders_202406而20240515仍走dn_old的readHost保证历史数据只读。5.3 用mycat-cli动态更新dateRange无需重启# 下载 mycat-cli 工具需 JDK8 wget https://github.com/MyCats/mycat-cli/releases/download/v1.0/mycat-cli-1.0.jar java -jar mycat-cli-1.0.jar -h 127.0.0.1 -P 9066 -u root -p 123456 \ -e reload config_all # 此命令触发 MyCat 重新加载 schema.xml立即生效 dateRange 变更效果验证插入create_time20240701→ 自动创建db_orders_202407并写入查询create_time20240510→ 仅从db_orders_old读取SELECT * FROM orders WHERE create_time 20240601→ 合并dn_new结果无跨库 JOIN 开销。我在线上用这套方案支撑过连续 14 个月的自动切库最大的教训是永远不要相信“下个月再建库”的计划一定要在partition-month.txt里提前写满未来 12 个月的映射——有次运维漏写20241212导致 12 月 1 日零点所有写请求 fallback 到 dn1雪崩了 3 分钟。现在我的习惯是每次上线前用脚本自动生成partition-month.txtfor m in $(seq -f %02g 1 12); do echo 2024$m$m; done conf/partition-month.txt希望帮到你。本文还有配套的精品资源点击获取