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

一起学 mybatis 你想不想来学习 mybatis? 学习其使用和源码呢?那么, 在博客园关注我吧!! 我自己打算把这个源码系列更新完毕, 同时会更新相应的注释。快去 star 吧!! mybatis最新源码和注释 github项目 在 mybatis 中, 对应 CRUD 的是四种节点: select where student_id=#{studentId, jdbcType=INTEGER} 其流程大体如下 多层递归解析 看的时候, 请对照代码来看, 详细讲解了前面三个节点的解析过程。 后面的类似, 可能有的递归层次加深了, 并大体的思路并没有改变。 3 可以定义节点来获取主键。 /** * 真正解析 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 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 =
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信