数据库路由中间件MyCat - 源代码篇(13)
此文已由作者张镐薪授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
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)的更多相关文章
- 数据库路由中间件MyCat - 源代码篇(1)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式.然后 ...
- 数据库路由中间件MyCat - 源代码篇(7)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.4 FrontendConnection前端连接 构造方法: public Fronte ...
- 数据库路由中间件MyCat - 源代码篇(15)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. public static void handle(String stmt, ServerConnectio ...
- 数据库路由中间件MyCat - 源代码篇(2)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...
- 数据库路由中间件MyCat - 源代码篇(17)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 调用processInsert(sc,schema,sqlType,origSQL,tableName,pr ...
- 数据库路由中间件MyCat - 源代码篇(14)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 对于表的dataNode对应关系,有个特殊配置即类似dataNode="distributed(d ...
- 数据库路由中间件MyCat - 源代码篇(4)
此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...
- 数据库路由中间件MyCat - 源代码篇(16)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 5. 路由模块 真正取得RouteResultset的步骤:AbstractRouteStrategy的ro ...
- 数据库路由中间件MyCat - 源代码篇(10)
此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.5 后端连接 3.5.2 后端连接获取与维护管理 还是那之前的流程, st=>st ...
随机推荐
- 【题解】POJ1934 Trip (DP+记录方案)
[题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...
- python 的print 用法
print(x,y) 等价于 import sys sys.stdout.write(str(x) + ' ' +str(y) + '\n') 从语法上讲,调用python3.0 的print 函数有 ...
- 负载均衡,会话保持,session同步(转)
一,什么负载均衡一个新网站是不要做负载均衡的,因为访问量不大,流量也不大,所以没有必要搞这些东西.但是随着网站访问量和流量的快速增长,单台服务器受自身硬件条件的限制,很难承受这么大的访问量.在这种情况 ...
- Java for LeetCode 092 Reverse Linked List II
Reverse a linked list from position m to n. Do it in-place and in one-pass. For example: Given 1-> ...
- luoguP3066 [USACO12DEC]逃跑的BarnRunning
luoguP3066 [USACO12DEC]逃跑的BarnRunning 题目大意 给定一棵n个节点的树和参数L,查询每个节点子树中到达该节点距离<=L的数量(包括该节点) 偏模板的主席树 P ...
- Spring Boot2.0之整合JSP
首先不建议整合JSP哈,spring boot 对jsp的支持力度不大. 内置tomcat不支持jsp. 注意:在创建项目时候一定是war类型的,而不是跟之前那个freemarker那种jar类型. ...
- 算法(Algorithms)第4版 练习 1.3.21
方法实现: //1.3.21 /** * find if some node in the list has key as its item field * * @param list the lin ...
- 计算机中丢失OPENGL.dll
开发OpenGL项目时,在VS开发环境下可能会出现如图所示的错误. 在c:\windows\system32和SysWow64文件夹下存在opengl32.dll,此时,所写程序能够正常编译,但是,程 ...
- python增删改查zabbix主机等
摘自: http://www.jianshu.com/p/e087cace8ddf 一.API简介 Zabbix API是在1.8版本中开始引进并且已经被广泛应用.所有的Zabbix移动客户端都是基于 ...
- css书写规则
无规矩不成方圆,不管有多少人共同参与同一项目,一定要确保每一行代码都像是同一个人编写的 不要在自闭合(self-closing)元素的尾部添加斜线 不要省略可选的结束标签(closing tag)(例 ...