简介

在上两篇文中,我们探索了SQLToken和真实SQL的生成的想关代码,本文继续来探索最开始的一个LogicSQL的生成,补全这一块拼图

源码探索

继续上面两篇的探索:

  • ShardingSphere 语句解析生成初探
  • ShardingSphere SQLToken 生成探索

其中生成真实的SQL有两个要素:

  • 逻辑表名到真实表名的映射:这个在SQLToken生成的
  • 拼接SQL语句时,对应的index位置,这个目前看来是在LogicSQL中就生成好了的

目前就还差index生成的东西,我们接下来就看看LogicSQL的相关代码:

寻找切入点

下面是LogicSQL的生成部分:

    private ExecutionContext createExecutionContext() {LogicSQL logicSQL = createLogicSQL();SQLCheckEngine.check(logicSQL.getSqlStatementContext().getSqlStatement(), logicSQL.getParameters(), metaDataContexts.getMetaData(connection.getSchemaName()).getRuleMetaData().getRules(), connection.getSchemaName(), metaDataContexts.getMetaDataMap(), null);ExecutionContext result = kernelProcessor.generateExecutionContext(logicSQL, metaDataContexts.getMetaData(connection.getSchemaName()), metaDataContexts.getProps());findGeneratedKey(result).ifPresent(generatedKey -> generatedValues.addAll(generatedKey.getGeneratedValues()));return result;}private LogicSQL createLogicSQL() {List<Object> parameters = new ArrayList<>(getParameters());SQLStatementContext<?> sqlStatementContext = SQLStatementContextFactory.newInstance(metaDataContexts.getMetaDataMap(), parameters, sqlStatement, connection.getSchemaName());return new LogicSQL(sqlStatementContext, sql, parameters);}

但通过debug看到相关的东西其实之前就生成好了:

其中的preparedStatement就有了相关的index信息,看来是在某一步就初始化好了的,我们找到对应的初始化语句,如下:

# ShardingSpherePreparedStatement.javaprivate ShardingSpherePreparedStatement(final ShardingSphereConnection connection, final String sql,final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability, final boolean returnGeneratedKeys) throws SQLException {if (Strings.isNullOrEmpty(sql)) {throw new SQLException(SQLExceptionConstant.SQL_STRING_NULL_OR_EMPTY);}this.connection = connection;metaDataContexts = connection.getContextManager().getMetaDataContexts();this.sql = sql;statements = new ArrayList<>();parameterSets = new ArrayList<>();ShardingSphereSQLParserEngine sqlParserEngine = new ShardingSphereSQLParserEngine(DatabaseTypeRegistry.getTrunkDatabaseTypeName(metaDataContexts.getMetaData(connection.getSchemaName()).getResource().getDatabaseType()));// 这里进行生成的sqlStatement = sqlParserEngine.parse(sql, true);parameterMetaData = new ShardingSphereParameterMetaData(sqlStatement);statementOption = returnGeneratedKeys ? new StatementOption(true) : new StatementOption(resultSetType, resultSetConcurrency, resultSetHoldability);JDBCExecutor jdbcExecutor = new JDBCExecutor(metaDataContexts.getExecutorEngine(), connection.isHoldTransaction());driverJDBCExecutor = new DriverJDBCExecutor(connection.getSchemaName(), metaDataContexts, jdbcExecutor);rawExecutor = new RawExecutor(metaDataContexts.getExecutorEngine(), connection.isHoldTransaction(), metaDataContexts.getProps());// TODO Consider FederateRawExecutorfederateExecutor = new FederateJDBCExecutor(connection.getSchemaName(), metaDataContexts.getOptimizeContextFactory(), metaDataContexts.getProps(), jdbcExecutor);batchPreparedStatementExecutor = new BatchPreparedStatementExecutor(metaDataContexts, jdbcExecutor, connection.getSchemaName());kernelProcessor = new KernelProcessor();}

我们再往前找找,看到是在OrderRepositoryImpl.java中进行触发的:

# OrderRepositoryImpl.java@Overridepublic Long insert(final Order order) throws SQLException {String sql = "INSERT INTO t_order (user_id, address_id, status) VALUES (?, ?, ?)";try (Connection connection = dataSource.getConnection();PreparedStatement preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {preparedStatement.setInt(1, order.getUserId());preparedStatement.setLong(2, order.getAddressId());preparedStatement.setString(3, order.getStatus());preparedStatement.executeUpdate();try (ResultSet resultSet = preparedStatement.getGeneratedKeys()) {if (resultSet.next()) {order.setOrderId(resultSet.getLong(1));}}}return order.getOrderId();}

那我们就继续探索:sqlStatement = sqlParserEngine.parse(sql, true);

我们一直跟着下去,来到一个SQL处理的相关类:MySQLStatementParser.java

其给人的第一个感觉是相当的复杂,我们跟着debug下去,看到进入到相关的insert处理的分支

         case XA:enterOuterAlt(_localctx, 1);{setState(1246);_errHandler.sync(this);switch ( getInterpreter().adaptivePredict(_input,0,_ctx) ) {case 1:{setState(1146);select();}break;case 2:{setState(1147);insert();}break;

跟着下去,来到insert语句处理具体函数:

# MySQLStatementParser.javapublic final InsertContext insert() throws RecognitionException {InsertContext _localctx = new InsertContext(_ctx, getState());enterRule(_localctx, 2, RULE_insert);int _la;try {enterOuterAlt(_localctx, 1);{setState(1258);// Insert相关处理match(INSERT);setState(1259);insertSpecification();setState(1261);_errHandler.sync(this);_la = _input.LA(1);if (_la==INTO) {{setState(1260);// into 相关处理match(INTO);}}setState(1263);// 表名相关处理tableName();setState(1265);_errHandler.sync(this);_la = _input.LA(1);if (_la==PARTITION) {{setState(1264);partitionNames();}}setState(1270);_errHandler.sync(this);switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) {case 1:{setState(1267);// values相关处理insertValuesClause();}break;case 2:{setState(1268);setAssignmentsClause();}break;case 3:{setState(1269);insertSelectClause();}break;}setState(1273);_errHandler.sync(this);_la = _input.LA(1);if (_la==ON) {{setState(1272);onDuplicateKeyClause();}}}}catch (RecognitionException re) {_localctx.exception = re;_errHandler.reportError(this, re);_errHandler.recover(this, re);}finally {exitRule();}return _localctx;}

在上面的函数中,我们大意看到几个比较关键的处理函数:

  • Insert相关处理 : match(INSERT);
  • into 相关处理 : match(INTO);
  • 表名相关处理 : tableName();
  • values相关处理 : insertValuesClause();

其规则跟下来有点复杂了,有循环和嵌套处理的,目前是梳理不清楚了

但其大意都是得到对应的开始和结束位置之类的,如下图:

最终得到结果如下:

到结果后,相关的返回函数如下:

@RequiredArgsConstructor
public final class SQLParserExecutor {private final String databaseType;/*** Parse SQL.* * @param sql SQL to be parsed* @return parse tree*/public ParseTree parse(final String sql) {ParseASTNode result = twoPhaseParse(sql);if (result.getRootNode() instanceof ErrorNode) {throw new SQLParsingException("Unsupported SQL of `%s`", sql);}return result.getRootNode();}
}

result.getRootNode() 如下:

@RequiredArgsConstructor
public final class ParseASTNode implements ASTNode {private final ParseTree parseTree;/*** Get root node.* * @return root node*/public ParseTree getRootNode() {return parseTree.getChild(0);}
}

而result的结果如下图,getChild(0)就是得到上面我们Insert解析后得到的结果

总结

感觉看的迷迷糊糊的,很多地方目前还不能很好的理解

但我们起码通过本次的探索知道了真实SQL的关键路径:

  • 通过原始的LogicSQL语句,经过的ShardingSphere的语法树解析,得到对应的各个部分的元数据,如开始和结束index
  • 根据语法树解析结果,得到对应的SQLToken,其中包含了如分库分表中的逻辑表到真实表的映射等关键信息
  • 根据SQLToken生成真实的SQL

ShardingSphere LogicSQL 的生成探索相关推荐

  1. SharingSphere 源码解析 -- 真实SQL生成探索

    SharingSphere 源码解析 – 真实SQL生成探索 简介 在上一篇文章中,我们探索了ShardingSphere JDBC Mybatis示例执行的一个大致的过程,找到了SQL处理的关键节点 ...

  2. 条形码/二维码生成探索

    条形码/二维码生成探索 所用依赖 <!--条形码生成依赖(轻量型,推荐使用这个)(生成条码的同时会把信息生成到条形码下)--><dependency><groupId&g ...

  3. ShardingSphere 语句解析生成初探

    简介 在上篇文章中,我们找到了一个逻辑SQL转换到真实SQL的关键路径代码,本篇文中,我们就上篇基础上,来探索语句解析生成的一些细节 源码解析 语句的关键解析生成的代码如下: @RequiredArg ...

  4. shardingsphere配置id生成策略无效

    记一次shardingsphere雪花算法无效. 我的配置如下: spring:shardingsphere:datasource:ds:driver-class-name: com.mysql.jd ...

  5. ShardingSphere JDBC 语句执行初探

    简介 在前几篇文中,我们基于源码就ShardingSphere的核心功能给运行了一遍,本篇文章开始,我们开始探索源码,看看ShardingSphere是如何进行工作的 概览 开始之前,我们先思考这次探 ...

  6. textbox如何在输入完成后再进行判断_单招不好使,连招才管用:为Android应用生成高质量测试输入...

    从我的一个朋友说起 曾经有一个朋友热爱艺术,经常在PxxxHub等等一系列艺术电影网站上下载观看艺术电影.但是他是一个自私的人,不愿意与别人分享,甚至不愿让自己的女朋友看到自己手机上存储的艺术电影.所 ...

  7. mysql主从shardingsphere分库分表

    问题: 1. 公司的mysql主从复制方式怎么查看--这个命令在哪敲 2.公司扩容一个从的时候怎么做的?-- 3.公司主从架构模式是什么样的?几主几从 4.公司的业务场景有木有要求写后立马查出数据的 ...

  8. 【更新】深度学习推荐系统

    其他博客:笔记1.博客2 文章目录 第一章.互联网的增长引擎--推荐系统 第二章.前深度学习时代--推荐系统的进化之路 第三章.浪潮之巅--深度学习在推荐系统中的应用 3.1 深度学习推荐模型的演化关 ...

  9. 音乐 美术 劳技 计算机教研组工作总结,小班教研组工作总结

    学习是为了更好地实践.在我们转变观念的同时,我们也通过日常活动每个环节的,体现二期课改的精神.幼儿园小班教研组工作总结如下,快随你出国留学网小编一起来了解下. 幼儿园小班教研组工作总结 我们小班组全体 ...

最新文章

  1. 本蒟蒻对于二分图一些定理的理解
  2. EasyDarwin开源音频解码项目EasyAudioDecoder:EasyPlayer Android音频解码库(第二部分,封装解码器接口)...
  3. centos配置oracle自启,centos 下配置oracle11gR2开机自启
  4. 为什么应该在业务层实现管道模式,而不用ASP.NET Core Middleware实现 | 2点原因和实现方式...
  5. LeetCode--171--Excel表列序号
  6. git安装后找不见版本_结果发现git版本为1.7.4,(git --version)而官方提示必须是1.7.10及以后版本...
  7. sql中变量用法_SQL变量:基础和用法
  8. Eclipse — 快速生成提示代码和快速导包
  9. JavaScript 使用指定字符格式化整数
  10. -bash: /usr/local/miniconda2/bin/conda: /home/hadoop/miniconda2/bin/python: bad interpreter: No such
  11. 谁是全球芯片行业的“麒麟才子”?得之可得天下!
  12. 线性代数的视角理解LSR(least square regression)的参数评估算法本质
  13. 仿真及设计工具下载安装方法详细说明
  14. 国际数学日 | 有π的日子,来一场数学派对
  15. Java基础知识每日总结(19)---Java输入输出流、文件、递归
  16. 中国异丁酸酐(CAS+97-72-3)行业市场供需与战略研究报告
  17. matlab中发现一特么别好用的画三维图函数ezmesh()
  18. C语言基础位运算符号
  19. 保姆式教你在Win10系统下安装Mac虚拟机
  20. 【拓展】这篇文章把TCP/IP讲绝了!

热门文章

  1. jquery背景动画插件使用
  2. 取英文名字的几个规则
  3. Visual Studio无法推送提交到Github的解决方法
  4. Non-parseable POM C:\Users\admin\.m2\repository\org\springframework问题解决方案
  5. 【报告分享】2021企业营销数字化转型研究报告.pdf(附下载链接)
  6. 【实践篇】推荐系统之矩阵分解模型-腾讯技术
  7. 【实践】CTR预估在动态样式建模和特征表达学习方面的进展
  8. 【数据结构与算法基础】二叉搜索树和平衡二叉树
  9. Leetcode每日一题:7.整数反转
  10. CCF认证2014-9-2 画图