第三章-Mybatis源码解析-以xml方式走流程-mapper解析(四)

3.2.2.7 selectKey解析

回到 XMLStatementBuilder.processSelectKeyNodes 的方法

java 复制代码
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
    // 拿到所有 selectKey 节点
    List<XNode> selectKeyNodes = context.evalNodes("selectKey");
    if (configuration.getDatabaseId() != null) {
        parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
    }
    // 解析selectKey节点
    parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
    // 遍历并移除selectKey节点,防止干扰<insert>主节点后续解析流程
    removeSelectKeyNodes(selectKeyNodes);
}

/** 
parentId 就是上级节点id,其实就是<insert id={parentId}>标签的id;
parameterTypeClass 也是<insert>标签上设置的参数类型
langDriver 就是 XMLLanguageDriver
skRequiredDatabaseId 一般情况下为 null
*/
private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
    for (XNode nodeToHandle : list) {
        // 给selectKey 语句生成一个以"!selectKey"结尾的id
        String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
        // databaseId, skRequiredDatabaseId 这两个值一般为null,实际生产也基本为null
        String databaseId = nodeToHandle.getStringAttribute("databaseId");

        if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
            // 两种情况会走到这里:1.如果configuration 中没有当前 id 的statement;2.如果有 statement,但是databaseId 为  null
            parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
        }
    }
}

private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
    // 下面这一段都是获取开发时对selectKey配置的几个属性,各属性的值前面也有介绍,或者自己去官网捞出来看
    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,看章节`3.2.2.6`
    SqlSource sqlSource = .createSqlSource(configuration, nodeToHandle, parameterTypeClass);
    SqlCommandType sqlCommandType = SqlCommandType.SELECT;
    // 创建 MappedStatement 并添加到 configuration 中,看章节`3.2.2.6`
    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);
    // 再从 configuration 中把 刚创建的 MappedStatement 对象取出来
    MappedStatement keyStatement = configuration.getMappedStatement(id, false);
    // 生成 SelectKeyGenerator 并存放到 configuration 的相应 HashMap 中
    configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}

private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
    for (XNode nodeToHandle : selectKeyNodes) {
        // 遍历并移除selectKey节点
        nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
    }
}

3.3 总结

现在可以回答本章刚开始的几个问题了。

1、谁来解析?

答:由 XMLMapperBuilder类来解析

2、用什么解析?

答:内部通过XPath来解析xml

3、解析成什么?

答:解析成 SqlSource

4、解析结果如何存放?

答:最终通过 MappedStatement 来包装,并存放在Configuration中

5、最终用途?

答:待执行器执行sql时使用

后续将通过抖音视频/直播的形式分享技术,由于前期要做一些准备和规划,预计2024年6月开始,欢迎关注,如有需要或问题咨询,也可直接抖音沟通交流。

相关推荐
Boilermaker19922 小时前
[Java 并发编程] Synchronized 锁升级
java·开发语言
Cherry的跨界思维2 小时前
28、AI测试环境搭建与全栈工具实战:从本地到云平台的完整指南
java·人工智能·vue3·ai测试·ai全栈·测试全栈·ai测试全栈
alonewolf_992 小时前
JDK17新特性全面解析:从语法革新到模块化革命
java·开发语言·jvm·jdk
一嘴一个橘子2 小时前
spring-aop 的 基础使用(啥是增强类、切点、切面)- 2
java
sheji34163 小时前
【开题答辩全过程】以 中医药文化科普系统为例,包含答辩的问题和答案
java
恋爱绝缘体13 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
wszy18093 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos
wszy18094 小时前
顶部标题栏的设计与实现:让用户知道自己在哪
java·python·react native·harmonyos
程序员小假4 小时前
我们来说一下无锁队列 Disruptor 的原理
java·后端
资生算法程序员_畅想家_剑魔5 小时前
Kotlin常见技术分享-02-相对于Java 的核心优势-协程
java·开发语言·kotlin