MyCat + PostgreSQL不支持二级子表分片

一、概述

最近开始学习Mycat,希望用它来实现多种数据库的分片(Sharding)。但当数据库为PostgreSQL时,却发现二级子表始终无法数据分片。经分析Mycat源码及简单测试,基本确定Mycat目前版本尚不支持非Mysql的二级子表分片。

按Mycat的解释,二级子表是指父表的父表不为空的表。

二、问题重现

测试环境为:Mycat 1.6.6.1,逻辑库为MySql5.7,两个PostgreSQL 10.6节点。

有三个表组成E-R分片:父表PERSON(主键ID),子表CARD(主键ID,外键PERSON_ID),二级子表CRAD_ITEM(主键CID,外键CID)。

具体配置见schema.xml: 

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
        <table name=PERSON" primaryKey="ID" dataNode="dn1,dn2" rule="mod-long">
            <childTable name="CARD" primaryKey="ID" joinKey="PERSON_ID" parentKey="ID">
                <childTable name="CARD_ITEM" joinKey="CID" parentKey="ID" />
            </childTable>
        </table>
    </schema>
    <dataNode name="dn1" dataHost="MyCat_PG_1" database="shard1" />
    <dataNode name="dn2" dataHost="MyCat_PG_2" database="shard2" />
    <dataHost name="MyCat_PG_1" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="postgresql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
        <heartbeat>select 1</heartbeat>
        <writeHost host="hostM1" url="jdbc:postgresql://192.168.64.185:5432/shard1" user="shard1" password="123456">
        </writeHost>
    </dataHost>
    <dataHost name="MyCat_PG_2" maxCon="1000" minCon="10" balance="0"
              writeType="0" dbType="postgresql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
        <heartbeat>select 1</heartbeat>
        <writeHost host="hostM2" url="jdbc:postgresql://192.168.64.186:5432/shard2" user="shard2" password="123456">
        </writeHost>
    </dataHost>
</mycat:schema>

测试过程中,向父表PERSON插入数据成功,向子表CARD插入数据也成功,但向二级子表CARD_ITEM插入时报1064错误:

mysql> insert into person(id, num) values(5, '5555555');
Query OK, 1 row affected (0.14 sec)
 OK!

mysql> insert into card(id, person_id) values(52, 5);
Query OK, 1 row affected (0.03 sec)
 OK!

mysql> insert into card_item(cid, data) values(52, 'It is 52');
ERROR 1064 (HY000): can't find (root) parent sharding node for sql:insert into card_item(cid, data) values(52, 'It is 52')

三、分析

尝试过不同配置几次,始终报这个错误。无奈下只好去研究源码,报错的地方是io.mycat.route.util.RouterUtil的方法processERChildTable()。

在该方法中,如果要向二级子表中插入记录,要判别对应的父表(根节点)在哪个dataNode,该语句是:

    final String findRootTBSql = tc.getLocateRTableKeySql().toLowerCase() + joinKeyVal;

跟踪到该处时,变量findRootTBSql值为:

select `person`.id from `card`,`person` where `person`.id=`card`.person_id and  `card`.id=52;

到这里已基本知道原因,是Mycat将每个表名都以“`”引起来了。这种语法只有mysql支持,而PostgreSQL和Oracle均不支持,所以报错。

进一步的尝试是修改该方法,将变量findRootTBSql中的“`”强行去掉,但之后插入二级子表时仍然报错,查看mycat.log,错误信息是:

2018-11-21 10:31:07.509  WARN [BusinessExecutor2] (io.mycat.backend.mysql.nio.handler.FetchStoreNodeOfChildTableHandler.executeException(FetchStoreNodeOfChildTableHandler.java:268)) - executeException   
java.io.UnsupportedEncodingException: unsupported yet

再一直跟踪,错误是在类io.mycat.backend.jdbc.JDBCConnection的query(String)方法抛出的,估计开发人员也认为目前不能解决。代码如下:

    @Override
    public void query(final String sql) throws UnsupportedEncodingException {
        if(respHandler instanceof ConnectionHeartBeatHandler)
        {
            justForHeartbeat(sql);
        }    else
        {
            throw new UnsupportedEncodingException("unsupported yet ");
        }
    }

只好期待MyCat以后的版本来解决了。

四、结论

目前的MyCat版本(1.6.6.1),在以JDBC连接非MySql数据库(比如PostgreSQL)时,不支持二级子表的分片。

原文地址:https://www.cnblogs.com/wggj/p/9994020.html