目 录CONTENT

文章目录

从ShardingJDBC到MyCAT:实战带你吃透分库分表中间件

冰点
2025-10-20 / 0 评论 / 0 点赞 / 14 阅读 / 45911 字

大家好,我是冰点。之前咱们花了不少时间啃ShardingJDBC,从基础配置到分片策略实战,也算把“代码层分库分表”的逻辑摸透了。但最近有朋友问我:“如果不想在项目里嵌中间件,想搞个独立的服务来管理分库分表,有没有合适的工具?” 这时候我第一个想到的,就是今天要聊的主角——MyCAT。

其实刚开始接触MyCAT时,我总把它和ShardingJDBC搞混:都是做分库分表,都支持多种分片规则,甚至连配置项都有几分相似。但越往后用越发现,二者的定位完全不同——ShardingJDBC是“嵌入式”的,得跟业务代码绑在一起;而MyCAT是“独立服务”,应用只需要像连MySQL一样连它就行,根本不用关心后端有多少个真实数据库。今天我就以第一人称的实战经历,带着大家从ShardingJDBC的视角切入,一步步搞懂MyCAT的玩法,避免大家走我之前踩过的坑。

一、先唠唠MyCAT和ShardingJDBC的“核心区别”

在动手配MyCAT之前,我觉得有必要先把它和ShardingJDBC的差异掰扯清楚——这是我当初走弯路的关键:最开始用MyCAT时,总下意识按ShardingJDBC的思路去配,结果越配越乱。后来画了张表对比,才彻底理清二者的定位:

对比维度

ShardingJDBC

MyCAT

我的实战感受

部署方式

嵌入式(依赖Jar包)

独立服务(需单独部署)

ShardingJDBC改代码就得重新发版,MyCAT改配置重启服务就行,对业务影响小

接入方式

项目中配置数据源、分片规则

应用直接连MyCAT(像连MySQL)

用MyCAT时,我项目里的MySQL连接地址改个IP端口就搞定,不用动一行业务代码

功能侧重

轻量分片、读写分离(代码层控制)

全量分库分表+分布式事务+高可用(服务层管理)

之前用ShardingJDBC做分布式事务,得配Seata;MyCAT自带部分事务支持,省了不少事

学习成本

需懂Java代码+配置文件

需懂独立服务配置+SQL路由逻辑

对非Java开发友好,我之前带运维同事配MyCAT,他不用看代码也能上手

简单说:如果你的项目是Java栈,想轻量集成、灵活控制分片逻辑,ShardingJDBC更合适;如果想脱离业务独立部署,或者团队里有非Java开发,MyCAT会更省心。我最近做的一个电商项目,就是因为后端有Python脚本要读库,果断从ShardingJDBC换成了MyCAT——脚本只需要连MyCAT的地址,根本不用管后端12个分库怎么分布。

二、实战准备:我踩过的“环境坑”要避开

跟ShardingJDBC比,MyCAT的环境准备多了一步“部署独立服务”,但其实不难。不过我当初因为没注意版本兼容,踩了个小坑:一开始用JDK17跑MyCAT 1.6,结果启动直接报“类加载异常”,后来查文档才知道MyCAT 1.6只支持JDK8,换成JDK8立马就好了。这里把我整理的“避坑版”准备步骤分享给大家:

1. 基础环境(必看兼容表)

组件

推荐版本

我踩过的坑

JDK

1.8(MyCAT 1.6/2.0都支持)

别用JDK11+,会报类缺失

MySQL

5.7/8.0

我用MySQL8.0时,要把MyCAT的dbDriver设为“native”,不然连不上

MyCAT

1.6.7.6(稳定版)

别追最新版,2.0虽然支持K8s,但部分配置项和1.6不兼容,新手容易懵

2. 部署MyCAT(比ShardingJDBC多一步)

ShardingJDBC是下Jar包、写配置文件就行,MyCAT得先下安装包部署:

  • 第一步:从MyCAT官网下载压缩包(我下的是1.6.7.6的linux版本),解压到 /usr/local/mycat 目录;

  • 第二步:改权限——我当初直接用root启动,结果报“权限不足”,后来执行 chmod -R 755 /usr/local/mycat 才好;

  • 第三步:先别启动!先配核心配置文件(这才是重点,跟ShardingJDBC的YML配置思路完全不同)。

三、核心配置实战:对照ShardingJDBC学MyCAT

这部分是重点。我会拿之前ShardingJDBC的“用户表分库分表”案例当对照,教大家怎么用MyCAT实现同样的需求——毕竟有参照物,学起来更快。

先回顾下需求:用户表(user)按id分3个库,每个库按create_time分2个表,分片规则和之前ShardingJDBC保持一致:

  • 分库规则:id % 3 → 对应dn1、dn2、dn3三个数据节点;

  • 分表规则:create_time按月分片(2024-01到2024-12,每月一个表)。

1. 第一步:配schema.xml(对应ShardingJDBC的数据源配置)

ShardingJDBC里要在YML里写dataSources和shardingRule,MyCAT则用schema.xml定义“逻辑库-数据节点-真实数据库”的映射。我第一次写这个文件时,总搞混dataNode和dataHost,后来发现其实很简单:

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- 逻辑库:对应ShardingJDBC的logicDatabaseName,应用连的就是这个库 -->
    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
        <!-- 用户表配置:对应ShardingJDBC的tableRule -->
        <table name="user" 
               primaryKey="id" 
               dataNode="dn1,dn2,dn3"  <!-- 分库对应的节点 -->
               rule="mod-long"         <!-- 分库规则(按id取模) -->
               subTables="user_${202401..202412}"> <!-- 分表:按月命名,对应ShardingJDBC的tableShardingStrategy -->
        </table>
    </schema>

    <!-- 数据节点:dn1对应localhost1主机的mycat_db1库,类似ShardingJDBC的dataSource -->
    <dataNode name="dn1" dataHost="localhost1" database="mycat_db1" />
    <dataNode name="dn2" dataHost="localhost1" database="mycat_db2" />
    <dataNode name="dn3" dataHost="localhost1" database="mycat_db3" />

    <!-- 数据主机:定义真实MySQL地址,类似ShardingJDBC的dataSource配置 -->
    <dataHost name="localhost1" 
              maxCon="50" minCon="2" 
              balance="1"  <!-- 读写分离:1表示读请求分发到从库,ShardingJDBC要配readwrite-splitting -->
              writeType="0" 
              dbType="mysql" 
              dbDriver="native">
        <!-- 心跳检测:比ShardingJDBC多的配置,确保MySQL存活 -->
        <heartbeat>select 1</heartbeat>
        <!-- 主库:写操作走这里 -->
        <writeHost host="hostM1" url="192.168.3.100:3306" user="root" password="123456">
            <!-- 从库:读操作走这里,ShardingJDBC要配slave数据源 -->
            <readHost host="hostS1" url="192.168.3.101:3306" user="root" password="123456" />
        </writeHost>
    </dataHost>
</mycat:schema>

这里有个点要跟大家强调:ShardingJDBC的分表得在代码里写tableShardingStrategy,而MyCAT直接用subTables配通配符就行,比如user_${202401..202412},就代表2024年1月到12月的分表,比ShardingJDBC更简洁。

2. 第二步:配rule.xml(对应ShardingJDBC的分片规则)

ShardingJDBC的分片规则写在YML的shardingRule里,MyCAT则用rule.xml单独管理,还支持把规则拆成配置文件(比如自动范围分片的规则写在txt里)。我当初最喜欢这个设计,因为规则多了之后,单独维护比堆在一个YML里清爽多了。

就拿我们需求里的“id分库”和“时间分表”来说,rule.xml的配置是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <!-- 分库规则:mod-long,对应ShardingJDBC的database-strategy -->
    <tableRule name="mod-long">
        <rule>
            <columns>id</columns> <!-- 分片字段:id -->
            <algorithm>mod-long</algorithm> <!-- 分片算法 -->
        </rule>
    </tableRule>

    <!-- 分表规则:sharding-by-month,对应ShardingJDBC的table-strategy -->
    <tableRule name="sharding-by-month">
        <rule>
            <columns>create_time</columns> <!-- 分片字段:create_time -->
            <algorithm>partbymonth</algorithm> <!-- 分片算法 -->
        </rule>
    </tableRule>

    <!-- 分库算法:按id取模,3个节点(对应3个分库) -->
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <property name="count">3</property> <!-- 分库数量,ShardingJDBC要配databaseCount -->
    </function>

    <!-- 分表算法:按月分片,从2024-01-01开始 -->
    <function name="partbymonth" class="io.mycat.route.function.PartitionByMonth">
        <property name="dateFormat">yyyy-MM-dd</property> <!-- 日期格式 -->
        <property name="sBeginDate">2024-01-01</property> <!-- 起始日期,ShardingJDBC要配startDate -->
    </function>
</mycat:rule>

这里有个我当初踩过的“细节坑”:MyCAT的PartitionByMonth算法,默认是按“当前日期往前推N个月”来分片的,如果你想指定起始月份,必须配sBeginDate——之前我没配这个,结果分表直接从当前月份开始,导致2024-01的数据插不进去,查了半天日志才发现问题。

3. 第三步:配server.xml(对应ShardingJDBC的属性配置)

ShardingJDBC的一些全局属性(比如sql.show、props)写在YML里,MyCAT则用server.xml配置用户、端口、安全策略这些。我觉得最有用的是“防火墙配置”,比ShardingJDBC的SQL黑名单更灵活:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
    <system>
        <!-- 端口配置:8066是应用访问端口,9066是管理端口 -->
        <property name="serverPort">8066</property>
        <property name="managerPort">9066</property>
        <!-- 字符集:跟ShardingJDBC一样,必须和MySQL一致,不然乱码 -->
        <property name="charset">utf8mb4</property>
        <!-- 慢SQL日志:超过600秒的SQL记录下来,方便排查 -->
        <property name="sqlExecuteTimeout">600</property>
    </system>

    <!-- 防火墙:比ShardingJDBC的SQL过滤更细 -->
    <firewall>
        <!-- 白名单:只允许192.168.3.0/24网段访问,避免陌生IP连库 -->
        <whitehost>
            <host host="192.168.3.%" user="root"/>
        </whitehost>
        <!-- 黑名单:禁止删表、锁表,之前用ShardingJDBC得自己写拦截器 -->
        <blacklist check="true">
            <property name="dropAllow">false</property> <!-- 禁止drop表 -->
            <property name="lockTableAllow">false</property> <!-- 禁止lock表 -->
        </blacklist>
    </firewall>

    <!-- 用户配置:应用连MyCAT的账号密码,类似MySQL的用户 -->
    <user name="root">
        <property name="password">123456</property>
        <property name="schemas">TESTDB</property> <!-- 能访问的逻辑库 -->
        <property name="readOnly">false</property> <!-- 可写 -->
    </user>
</mycat:server>

这里提个小技巧:MyCAT的managerPort(9066)特别好用,之前我想查看分库分表的路由情况,直接用mysql -h 127.0.0.1 -P 9066 -u root -p连上去,执行show @@route;就能看到SQL路由到哪个节点了,比ShardingJDBC的日志排查更直观。

四、实战测试:用ShardingJDBC的案例对比验证

配置完之后,我习惯用之前ShardingJDBC的测试案例来验证,这样能快速对比二者的差异。咱们就用“插入3条用户数据”来测试,看看MyCAT的路由是否正确:

1. 连接MyCAT(比ShardingJDBC多一步)

ShardingJDBC是项目里直接用DataSource连,MyCAT则需要用MySQL客户端连:

mysql -h 192.168.3.102 -P 8066 -u root -p123456

这里的IP是MyCAT服务器的地址,端口是8066,账号密码是server.xml里配的——连成功后,会显示“MyCAT Server version: 1.6.7.6”,跟连MySQL一模一样,应用代码里也不用改任何连接逻辑。

2. 建表+插入数据(和ShardingJDBC对比)

在MyCAT里执行建表语句:

CREATE TABLE user (
    id BIGINT NOT NULL PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT,
    create_time DATE NOT NULL
);

这里有个惊喜:ShardingJDBC需要手动建分库分表,而MyCAT会自动在dn1(mycat_db1)、dn2(mycat_db2)、dn3(mycat_db3)里创建对应的分表,比如mycat_db1里会有user_202401、user_202402……省了我不少事。

然后插入3条数据,跟之前ShardingJDBC的测试数据一样:

INSERT INTO user (id, name, age, create_time) VALUES 
(1, '张三', 20, '2024-01-15'),  -- id%3=1 → 分库dn2;时间2024-01 → 分表user_202401
(2, '李四', 22, '2024-02-20'),  -- id%3=2 → 分库dn3;时间2024-02 → 分表user_202402
(3, '王五', 25, '2024-03-10');  -- id%3=0 → 分库dn1;时间2024-03 → 分表user_202403

3. 验证路由(MyCAT的优势体现)

插入完之后,我需要验证数据是否分到了正确的库表。ShardingJDBC得去每个MySQL库查,而MyCAT可以直接用管理端口查路由:

  1. 连管理端口:mysql -h 192.168.3.102 -P 9066 -u root -p123456;

  2. 执行路由查询:explain INSERT INTO user (id, name, age, create_time) VALUES (1, '张三', 20, '2024-01-15');;

  3. 结果显示:DATA_NODE: dn2, TABLE: user_202401——跟预期完全一致,比ShardingJDBC查日志快多了。

再查一条数据试试:SELECT * FROM user WHERE id=1;,MyCAT会直接路由到dn2的user_202401表,不用扫描所有库表,效率和ShardingJDBC差不多。

五、我总结的“避坑指南”:MyCAT比ShardingJDBC多注意这3点

用下来我发现,MyCAT虽然部署简单,但有些细节比ShardingJDBC容易踩坑,我把自己的经验整理成了3条:

  1. 版本兼容一定要注意:JDK必须用1.8,MySQL8.0要配dbDriver="native",不然启动报错;ShardingJDBC对JDK版本宽容多了,11也能用。

  2. 分表不要漏配sBeginDate:用PartitionByMonth算法时,必须指定sBeginDate,不然默认从当前月份开始,历史数据插不进去;ShardingJDBC的month分片默认会包含所有月份,这点更友好。

  3. 心跳检测要配对:dataHost里的heartbeat SQL不能乱写,最好用select 1,之前我写了个复杂的查询,导致MyCAT误判MySQL宕机,自动切换到备用库了;ShardingJDBC没有心跳检测,得自己配健康检查。

六、最后聊聊:什么时候选MyCAT,什么时候选ShardingJDBC?

这阵子用下来,我大概总结出了二者的适用场景,大家可以根据自己的项目选:

  • 选ShardingJDBC的情况:如果你的项目是Java栈,想轻量集成,不想多部署一个服务,而且需要灵活的分片逻辑(比如自定义分片算法),ShardingJDBC更合适——我之前做的一个SpringBoot项目,用ShardingJDBC只加了3个依赖,改改YML就上线了。

  • 选MyCAT的情况:如果你的项目不是纯Java栈(比如有Python、Go脚本),或者想独立管理分库分表(比如运维团队负责中间件),MyCAT更省心——现在这个电商项目,Python脚本连MyCAT跟连MySQL一样,运维同事改分片规则也不用找开发,自己改改rule.xml就行。

其实不管是MyCAT还是ShardingJDBC,核心都是“把数据合理拆分到多个库表,解决单库单表的瓶颈”。咱们学的时候不用纠结哪个更好,而是要理解它们的设计思路,遇到不同场景能选对工具——这才是分库分表的核心能力。

对了,我把这次实战用的MyCAT配置文件(schema.xml、rule.xml、server.xml)整理成了模板,里面加了详细注释,大家直接改改IP、密码就能用。需要的话可以跟我说,我发你!

0

评论区