mybatis源码-Mapper解析之SQL 语句节点解析(一条语句对应一个MappedStatement) (3)

该过程中涉及到了多层递归, 同时还有多种节点类型, 还需要进行占位符的处理, 理解上还是比较费劲的, 举个栗子吧

<!--全部字段--> <sql> student_id, name, phone, email, sex, locked, gmt_created, gmt_modified </sql> <!--表名--> <sql> ${table} </sql> <!--refid可以使用${}--> <sql> from <include refid="${include_target}"/> </sql> <!--SQL--> <select resultMap="BaseResultMap"> select <include refid="Base_Column_List" /> <include refid="someinclude"> <property value="student"/> <property value="sometable"/> </include> where student_id=#{studentId, jdbcType=INTEGER} </select>

其流程大体如下

多层递归解析

看的时候, 请对照代码来看, 详细讲解了前面三个节点的解析过程。 后面的类似, 可能有的递归层次加深了, 并大体的思路并没有改变。

3

<insert>、<update>可以定义<selectKey>节点来获取主键。

/** * 真正解析 selectKey 的函数 */ private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) { // 开始时获取各个属性 String resultType = nodeToHandle.getStringAttribute("resultType"); Class<?> resultTypeClass = resolveClass(resultType); StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString())); String keyProperty = nodeToHandle.getStringAttribute("keyProperty"); String keyColumn = nodeToHandle.getStringAttribute("keyColumn"); boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER")); //defaults boolean useCache = false; boolean resultOrdered = false; KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; Integer fetchSize = null; Integer timeout = null; boolean flushCache = false; String parameterMap = null; String resultMap = null; ResultSetType resultSetTypeEnum = null; // 生成对应的 SqlSource SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass); SqlCommandType sqlCommandType = SqlCommandType.SELECT; // 使用 SqlSource 创建 MappedStatement 对象 builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null); id = builderAssistant.applyCurrentNamespace(id, false); MappedStatement keyStatement = configuration.getMappedStatement(id, false); // 添加到 Configuration 中, 并通过 executeBefore 还觉得是在sql之前执行还是之后执行 configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore)); }

其中涉及到

SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);

这个过程。

LanguageDriver 类有两个实现类

LanguageDriver及其实现类

默认是 XMLLanguageDriver。 可以通过 Configuration 的构造函数得出。

languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);

在 langDriver.createSqlSource 函数中, 会调用 parseScriptNode 函数

/** * 解析动态节点 * @return */ public SqlSource parseScriptNode() { // 首先判断是不是动态节点 MixedSqlNode rootSqlNode = parseDynamicTags(context); SqlSource sqlSource = null; if (isDynamic) { sqlSource = new DynamicSqlSource(configuration, rootSqlNode); } else { sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType); } return sqlSource; }

而其中, 需要判定是否为动态SQL, 其中, 有 $ 和动态 sql 的节点, 都会认为是动态SQL。

/** * 解析动态节点 * @param node * @return */ protected MixedSqlNode parseDynamicTags(XNode node) { List<SqlNode> contents = new ArrayList<>(); // 获取节点下的所有子节点 NodeList children = node.getNode().getChildNodes(); for (int i = 0; i < children.getLength(); i++) { // 获取节点 XNode child = node.newXNode(children.item(i)); if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) { // 如果有 $ , 则为动态sql节点 String data = child.getStringBody(""); TextSqlNode textSqlNode = new TextSqlNode(data); if (textSqlNode.isDynamic()) { contents.add(textSqlNode); isDynamic = true;// 标记为动态节点 } else { contents.add(new StaticTextSqlNode(data)); } } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628 // 子节点是标签, 则一定是动态sql节点。 根据nodeName, 生产不同的 NodeHandler String nodeName = child.getNode().getNodeName(); NodeHandler handler = nodeHandlerMap.get(nodeName); if (handler == null) { throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement."); } handler.handleNode(child, contents); isDynamic = true; } } return new MixedSqlNode(contents); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwjfz.html