此文已由作者张镐薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

4.配置模块

4.2 schema.xml

接上一篇,接下来载入每个schema的配置(也就是每个MyCat中虚拟化的数据库的配置): XMLSchemaLoader.java

private void loadSchemas(Element root) {
        NodeList list = root.getElementsByTagName("schema");    for (int i = 0, n = list.getLength(); i < n; i++) {
        Element schemaElement = (Element) list.item(i);        //读取各个属性
        String name = schemaElement.getAttribute("name");
        String dataNode = schemaElement.getAttribute("dataNode");
        String checkSQLSchemaStr = schemaElement.getAttribute("checkSQLschema");
        String sqlMaxLimitStr = schemaElement.getAttribute("sqlMaxLimit");        int sqlMaxLimit = -1;        //读取sql返回结果集限制
        if (sqlMaxLimitStr != null && !sqlMaxLimitStr.isEmpty()) {
            sqlMaxLimit = Integer.valueOf(sqlMaxLimitStr);
        }        // check dataNode already exists or not,看schema标签中是否有datanode
        String defaultDbType = null;        //校验检查并添加dataNode
        if (dataNode != null && !dataNode.isEmpty()) {
            List<String> dataNodeLst = new ArrayList<String>(1);
            dataNodeLst.add(dataNode);
            checkDataNodeExists(dataNodeLst);
            String dataHost = dataNodes.get(dataNode).getDataHost();
            defaultDbType = dataHosts.get(dataHost).getDbType();
        } else {
            dataNode = null;
        }        //加载schema下所有tables
        Map<String, TableConfig> tables = loadTables(schemaElement);        //判断schema是否重复
        if (schemas.containsKey(name)) {            throw new ConfigException("schema " + name + " duplicated!");
        }        // 设置了table的不需要设置dataNode属性,没有设置table的必须设置dataNode属性
        if (dataNode == null && tables.size() == 0) {            throw new ConfigException(                    "schema " + name + " didn't config tables,so you must set dataNode property!");
        }         SchemaConfig schemaConfig = new SchemaConfig(name, dataNode,
                tables, sqlMaxLimit, "true".equalsIgnoreCase(checkSQLSchemaStr));        //设定DB类型,这对之后的sql语句路由解析有帮助
        if (defaultDbType != null) {
            schemaConfig.setDefaultDataNodeDbType(defaultDbType);            if (!"mysql".equalsIgnoreCase(defaultDbType)) {
                schemaConfig.setNeedSupportMultiDBType(true);
            }
        }        // 判断是否有不是mysql的数据库类型,方便解析判断是否启用多数据库分页语法解析
        for (String tableName : tables.keySet()) {
            TableConfig tableConfig = tables.get(tableName);            if (isHasMultiDbType(tableConfig)) {
                schemaConfig.setNeedSupportMultiDBType(true);                break;
            }
        }        //记录每种dataNode的DB类型
        Map<String, String> dataNodeDbTypeMap = new HashMap<>();        for (String dataNodeName : dataNodes.keySet()) {
            DataNodeConfig dataNodeConfig = dataNodes.get(dataNodeName);
            String dataHost = dataNodeConfig.getDataHost();
            DataHostConfig dataHostConfig = dataHosts.get(dataHost);            if (dataHostConfig != null) {
                String dbType = dataHostConfig.getDbType();
                dataNodeDbTypeMap.put(dataNodeName, dbType);
            }
        }
        schemaConfig.setDataNodeDbTypeMap(dataNodeDbTypeMap);
        schemas.put(name, schemaConfig);
    }
}

首先读取schema每个配置属性项,并作有效性判断。比如默认的dataNode是否存在。只要验证之前读取的dataNode里面有没有就可以

private void checkDataNodeExists(Collection<String> nodes) {    if (nodes == null || nodes.size() < 1) {        return;
    }    for (String node : nodes) {        if (!dataNodes.containsKey(node)) {            throw new ConfigException("dataNode '" + node + "' is not found!");
        }
    }
}

之后载入所有的table和childTable:

private Map<String, TableConfig> loadTables(Element node) {    // Map<String, TableConfig> tables = new HashMap<String, TableConfig>();

    // 支持表名中包含引号[`] BEN GONG
    Map<String, TableConfig> tables = new TableConfigMap();
    NodeList nodeList = node.getElementsByTagName("table");    for (int i = 0; i < nodeList.getLength(); i++) {
        Element tableElement = (Element) nodeList.item(i);
        String tableNameElement = tableElement.getAttribute("name").toUpperCase();        //TODO:路由, 增加对动态日期表的支持
        String tableNameSuffixElement = tableElement.getAttribute("nameSuffix").toUpperCase();        if ( !"".equals( tableNameSuffixElement ) ) {                             if( tableNameElement.split(",").length > 1 ) {                throw new ConfigException("nameSuffix " + tableNameSuffixElement + ", require name parameter cannot multiple breaks!");
            }            //前缀用来标明日期格式
            tableNameElement = doTableNameSuffix(tableNameElement, tableNameSuffixElement);
        }        //记录主键,用于之后路由分析,以及启用自增长主键
        String[] tableNames = tableNameElement.split(",");
        String primaryKey = tableElement.hasAttribute("primaryKey") ? tableElement.getAttribute("primaryKey").toUpperCase() : null;        //记录是否主键自增,默认不是,(启用全局sequence handler)
        boolean autoIncrement = false;        if (tableElement.hasAttribute("autoIncrement")) {
            autoIncrement = Boolean.parseBoolean(tableElement.getAttribute("autoIncrement"));
        }        //记录是否需要加返回结果集限制,默认需要加
        boolean needAddLimit = true;        if (tableElement.hasAttribute("needAddLimit")) {
            needAddLimit = Boolean.parseBoolean(tableElement.getAttribute("needAddLimit"));
        }        //记录type,是否为global
        String tableTypeStr = tableElement.hasAttribute("type") ? tableElement.getAttribute("type") : null;        int tableType = TableConfig.TYPE_GLOBAL_DEFAULT;        if ("global".equalsIgnoreCase(tableTypeStr)) {
            tableType = TableConfig.TYPE_GLOBAL_TABLE;
        }        //记录dataNode,就是分布在哪些dataNode上
        String dataNode = tableElement.getAttribute("dataNode");
        TableRuleConfig tableRule = null;        if (tableElement.hasAttribute("rule")) {
            String ruleName = tableElement.getAttribute("rule");
            tableRule = tableRules.get(ruleName);            if (tableRule == null) {                throw new ConfigException("rule " + ruleName + " is not found!");
            }
        }        boolean ruleRequired = false;        //记录是否绑定有分片规则
        if (tableElement.hasAttribute("ruleRequired")) {
            ruleRequired = Boolean.parseBoolean(tableElement.getAttribute("ruleRequired"));
        }        if (tableNames == null) {            throw new ConfigException("table name is not found!");
        }        //distribute函数,重新编排dataNode
        String distPrex = "distribute(";        boolean distTableDns = dataNode.startsWith(distPrex);        if (distTableDns) {
            dataNode = dataNode.substring(distPrex.length(), dataNode.length() - 1);
        }        //分表功能
        String subTables = tableElement.getAttribute("subTables");        for (int j = 0; j < tableNames.length; j++) {
            String tableName = tableNames[j];
            TableConfig table = new TableConfig(tableName, primaryKey,
                    autoIncrement, needAddLimit, tableType, dataNode,
                    getDbType(dataNode),
                    (tableRule != null) ? tableRule.getRule() : null,
                    ruleRequired, null, false, null, null,subTables);             checkDataNodeExists(table.getDataNodes());            if (distTableDns) {
                distributeDataNodes(table.getDataNodes());
            }            //检查去重
            if (tables.containsKey(table.getName())) {                throw new ConfigException("table " + tableName + " duplicated!");
            }            //放入map
            tables.put(table.getName(), table);
        }        //只有tableName配置的是单个表(没有逗号)的时候才能有子表
        if (tableNames.length == 1) {
            TableConfig table = tables.get(tableNames[0]);            // process child tables
            processChildTables(tables, table, dataNode, tableElement);
        }
    }    return tables;
}

对于子表,有递归读取配置:

private void processChildTables(Map<String, TableConfig> tables,
            TableConfig parentTable, String dataNodes, Element tableNode) {        // parse child tables
        NodeList childNodeList = tableNode.getChildNodes();        for (int j = 0; j < childNodeList.getLength(); j++) {
            Node theNode = childNodeList.item(j);            if (!theNode.getNodeName().equals("childTable")) {                continue;
            }
            Element childTbElement = (Element) theNode;            //读取子表信息
            String cdTbName = childTbElement.getAttribute("name").toUpperCase();            String primaryKey = childTbElement.hasAttribute("primaryKey") ? childTbElement.getAttribute("primaryKey").toUpperCase() : null;             boolean autoIncrement = false;            if (childTbElement.hasAttribute("autoIncrement")) {
                autoIncrement = Boolean.parseBoolean(childTbElement.getAttribute("autoIncrement"));
            }
            boolean needAddLimit = true;            if (childTbElement.hasAttribute("needAddLimit")) {
                needAddLimit = Boolean.parseBoolean(childTbElement.getAttribute("needAddLimit"));
            }            String subTables = childTbElement.getAttribute("subTables");            //子表join键,和对应的parent的键,父子表通过这个关联
            String joinKey = childTbElement.getAttribute("joinKey").toUpperCase();            String parentKey = childTbElement.getAttribute("parentKey").toUpperCase();
            TableConfig table = new TableConfig(cdTbName, primaryKey,
                    autoIncrement, needAddLimit,
                    TableConfig.TYPE_GLOBAL_DEFAULT, dataNodes,
                    getDbType(dataNodes), null, false, parentTable, true,
                    joinKey, parentKey, subTables);            if (tables.containsKey(table.getName())) {                throw new ConfigException("table " + table.getName() + " duplicated!");
            }
            tables.put(table.getName(), table);            //对于子表的子表,递归处理
            processChildTables(tables, table, dataNodes, childTbElement);
        }
    }

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 从风控的角度解析如何防止客户刷单
【推荐】 web调试利器_fiddler

数据库路由中间件MyCat - 源代码篇(13)的更多相关文章

  1. 数据库路由中间件MyCat - 源代码篇(1)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式.然后 ...

  2. 数据库路由中间件MyCat - 源代码篇(7)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.4 FrontendConnection前端连接 构造方法: public Fronte ...

  3. 数据库路由中间件MyCat - 源代码篇(15)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. public static void handle(String stmt, ServerConnectio ...

  4. 数据库路由中间件MyCat - 源代码篇(2)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...

  5. 数据库路由中间件MyCat - 源代码篇(17)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 调用processInsert(sc,schema,sqlType,origSQL,tableName,pr ...

  6. 数据库路由中间件MyCat - 源代码篇(14)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 对于表的dataNode对应关系,有个特殊配置即类似dataNode="distributed(d ...

  7. 数据库路由中间件MyCat - 源代码篇(4)

    此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...

  8. 数据库路由中间件MyCat - 源代码篇(16)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 5. 路由模块 真正取得RouteResultset的步骤:AbstractRouteStrategy的ro ...

  9. 数据库路由中间件MyCat - 源代码篇(10)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.5 后端连接 3.5.2 后端连接获取与维护管理 还是那之前的流程, st=>st ...

随机推荐

  1. CF(439E - Devu and Birthday Celebration)莫比乌斯容斥

    题意:将n个糖果插入f-1个挡板分成f分(a1,a2,a3...af). 问有多少种分法能够使得gcd(a1,a2,a3...af)=1; 解法.莫比乌斯容斥,首先按1为单位分,这时候有C(n-1,f ...

  2. Java反射详解(转)

    原文地址:http://www.importnew.com/17616.html 动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化.比如众所 ...

  3. 负载均衡,会话保持,session同步(转)

    一,什么负载均衡一个新网站是不要做负载均衡的,因为访问量不大,流量也不大,所以没有必要搞这些东西.但是随着网站访问量和流量的快速增长,单台服务器受自身硬件条件的限制,很难承受这么大的访问量.在这种情况 ...

  4. Linux 下搭建 Sonatype Nexus Maven 私服

    一.为什么需要搭建mave私服 如果没有私服,我们所需的所有构件都需要通过maven的中央仓库和第三方的Maven仓库下载到本地,而一个团队中的所有人都重复的从maven仓库下 载构件无疑加大了仓库的 ...

  5. C#winform的datagridview设置选中行

    this.dataGridView1.CurrentCell = this.dataGridView1[colIndex, rowIndex];this.dataGridView1.BindingCo ...

  6. 《CSS权威指南(第三版)》---第三章 结构和层叠

    这章主要讲的是当某个对象被选择器多次提取使用样式之后的一些冲突性解决方案: 1.特殊性:指的是当多个效果作用的时候的最终选择: 这个规则用0,0,0,0来比较.其中:内联式是1,0,0,0  ID选择 ...

  7. LightOJ - 1151 Snakes and Ladders —— 期望、高斯消元法

    题目链接:https://vjudge.net/problem/LightOJ-1151 1151 - Snakes and Ladders    PDF (English) Statistics F ...

  8. 【Codeforces】Gym 101156G Non-Attacking Queens 打表

    题意 求$n\times n$的棋盘上放$3$个皇后使得互相不攻击的方案数 拓展是$m\times n$棋盘上放$k$皇后,暴力打表找到了公式 OEIS 代码 import java.math.Big ...

  9. ubuntu c++ 关机 重启 挂起 API

    #include <unistd.h> #include <linux/reboot.h> int main() { reboot(LINUX_REBOOT_MAGIC1, L ...

  10. OpenCV——Skewing

    // define head function #ifndef PS_ALGORITHM_H_INCLUDED #define PS_ALGORITHM_H_INCLUDED #include < ...