MyCat 分析02

3. 重点看默认的c.execute(stmt,ServerParse.SELECT)

3.1 首先检查连接状态是否关闭

3.2 检查当前的事务状态是否正常

3.3 检查是否已经选择过了DB,没选择过就return

3.4 兼容phpAdmin's ,支持对Mysql 元数据的模拟返回,information_schema

3.5 兼容MysqlWorkbench的处理

3.6 从MycatServer的实例的配置获取该db的schema,并且校验该schema不能为空

3.7 如果sql中指定了schema,则从sql中解析出schema,然后使用

3.8 执行routeEndExecuteSQL, 从mycatServer的配置中获取routeResultset ,路由集;

包含了SQL语义解析,SQL路由,SQL查询优化,SQL语句改写,全局ID生成

3.9 MycatServer初始化的时候,会新建一个RouteService,调用它的route方法解析,MycatServer的routeCache使用了ehcache

 

1.如果sqlType为SELECT,则先拼接出cachekey,然后从sqlRouteCache中获取出rrs,如果缓存sqlRouteCache中有值,则检查数据迁移的规则,调用checkMigrateRule,但是我们sqlType为SELECT,所以会直接返回,也就是会直接返回rrs路由结果集

2.调用isHitSql 获取命中sql的长度,过滤掉 空格 和 * 两种字符,匹配 mycat字符前缀标志Hintsql:"/** mycat: */",也就是命中mycat注解的sql

3.如果命中了Mycat注解的sql,就截取出sql来做路由分析,先组装成一个hintMap,然后截取出realSQL,调用hintHandler.route()来路由

本质上还是调用了AbstractRouteStrategy的route方法

4.开始route方法,如果schema有checkSQLschema的属性,就把表示schema的字符去掉。

5.处理一些路由之前的逻辑,全局序列号插入,父子表插入

6.开始SQL语句拦截,调用DefaultSQLInterceptor 的 interceptSQL处理,如果是fdbParser,就调用processEscape ;如果开启了全局表一致性检测,SQL语句分成了Insert,Update和DDL,但我们这个是查询,就会直接返回。

7. 判断如果日志级别是debug,并且loadData ,则该rrs就不缓存了,如果缓存的话,会极大降低性能。

8. 如果是DDL语句类型,分成几类处理 create table,create index, drop table, drop index, alter table, truncate table

9.检查是否有分片,如果没有分片,并且不是show语句,就执行单节点路由,直接获取第一个节点作为路由,RouteResultsetNode[0]

10.如果有多个分片,就调用routeNormalSqlWithAST,通过解析AST语法树来寻找路由

11.首先判断是否是只有mysql,如果是,则使用MysqlStatementParser,如果不是,则使用MycatStatementParser

12.调用parser.parseStatement()来解析,调用的是底层druid-1.0.26的SQLStatementParser.parseStatementList,根据不同的token类型

执行不同的parse操作,大概分为SELECT,UPDATE,CREATE,INSERT,DELETE,EXPLAIN,ALTER,DROP等操作。

13. 解析完成后返回statement,然后检查语句类型,如果是replace的语句,就直接抛出异常,不支持

14.根据schema,statement和visitor创建druidParser

14.1 判断如果statement 是多数据源的,就调用getDruidParserForMultiDB,创建对应的多数据源parser;从statement解析出表 ,判断表所在db的类型:直接解析对应的sql语句获取表 -- 字符串截取;然后汇总可能出现的db的类型,包括oracle , db2 ,mysql,sqlServer,postgresql

14.2 如果不是多数据源的,就根据sql语句类型,返回不同的parser,包括,DruidSelectParser, DruidInsertParser,DruidDeleteParser,DruidCreateTableParser,DruidUpdateParser,DruidAlterTableParser,DruidLockTableParser

15. 开始调用创建好的druidParser进行解析

15.1 设置sql为原始sql

15.2 通过visitor进行解析sql,只DruidLockTableParser有对应的实现--由于多表锁在分布式场景处理繁琐,应用场景较少,因此在此处对这种锁表语句进行拦截。解析sql的字符串,如果命令存在”,“,按照多表锁的语句处理,并且进一步验证是否符合多表锁的语法。

16. 通过statement 解析,覆盖了全部的parser :

16.1 DruidAlterTableParser: 把stmt转化成为SQLAlterTableStatement,然后通过截取字符串获取tableName,加入到ctx后返回

16.2 DruidCreateTableParser : 把stmt转化成MysqlCreateTableStatement,截取字符串获取tableName;如果schema包含tableName,

就加载出对应的tableConfig,然后从tableConfig中获取分表算法,如果是slotFunction,把sql填充到ctx

16.3 DruidDeleteParser : 把stmt转化的MysqlDeleteStatement , 字符串截取解析出tableName,设置到ctx

16.4 DruidInsertParser : 转化成MySqlInsertStatement,解析出tableName,设置到ctx;

如果不分库分表,就直接从schema中获取node[0],然后填充属性,最后放到RouteResultSet,设置路由完毕

如果是分库分表的,就要根据对应的tableName获取tableConfig,判断是否是子表,是子表继续获取 tableConfig,然后获取joinKey,以及joinKey的索引,并且校验子表不能批量插入;根据joinKey的索引获取joinKeyVal,调用RouterUtil.routeByERParentKey获取路由结果;

根据ER分片规则获取路由集合 : 判断是否有二级子表(父表不再有父表) ,根据父表配置,调用ruleCalculate计算路由,获取父表config的rule,并且获取对应的路由算法ruleAlgorithm,调用algorithm.calculate计算nodeIndex,然后计算nodeRange,根据某一种分表的方法,例如PartitionByDate,最后把获取的node列表,加入到routeNodeSet,返回结果

如果不是子表,就从表的配置获取partitionColumn,也就是分片列;如果是批量插入,就获取分片列在批量插入列中的索引;从批量插入语句中获取插入值列表,并且从分片路由中获取路由算法,然后循环插入值列表,根据该记录的分片列的索引,得到该记录的分片值。然后计算出对应的nodeIndex,并且加入到nodeValuesMap,最后循环加入到路由结果集RouteResultSetNode;

如果是单个插入:方法与上面同理,也是需要计算出对应的路由node,然后返回对应的路由结果集。

16.5 DruidSelectParser : 转化成SQLSelectStatement,然后转成MysqlSelectQueryBlock,调用parseOrderAggGroupMysql解析,本质是调用parseAggGroupCommon

获取selectList, 循环,如果是一个计算总数的expr,也就是sum和count,设置各种属性,添加到RouteResultSet;对于groupBy处理同上

判断如果是forUpdate或者是锁模式,rrs设置为运行在只读db

16.6 DruidUpdateParser : 限制update 只能支持一个分片表,超过就抛出异常;把入参的stmt转化成MysqlUpdateStatement,然后通过截取字符串获取tableName,再根据tableName从schema中获取TableConfig

1. 如果整个schema都不分库或者不分表,则直接从schema中获取dataNode,然后放到RouteResultSet中返回。

2. 如果是分表的,则获取分表的列 partitionColumn;如果是全局表,则路由集rrs返回全部的dataNodes;如果不是,则返回对应的dataNodes作为路由集结果。

+++++++++++++++++++++++++++++++++++++++++++++++

17. changeSql :改写sql ,只涉及DruidSelectParser

17.1 调用tryRoute() ,判断如果已经结束了路由,就直接返回;

17.2 如果没有表,select语句直接路由到任意一个节点

17.3 循环ctx中每个路由计算的unit,然后计算路由后的rrsTmp,并且循环把所有的rrsTmp中的node 加入到nodeSet。如果最后nodeSet为空,就直接抛出异常。最后设置finishRoute为true,返回结果

17.4 判断是mysql语句,就根据语句,初始化mysqlSelectQuery,判断如果需要加limit,就设置到mysqlSelectQuery中

17.5 从上面的limit对象获取offset和count,判断如果rrs的nodes个数大于1个,就需要changeLimit,设置rowCount = limitStart + limitSize

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值