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


    3.2.2.7 selectKey解析

    回到 XMLStatementBuilder.processSelectKeyNodes 的方法

    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节点,防止干扰主节点后续解析流程
        removeSelectKeyNodes(selectKeyNodes);
    }
    
    /** 
    parentId 就是上级节点id,其实就是标签的id;
    parameterTypeClass 也是标签上设置的参数类型
    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());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    3.3 总结

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

    1、谁来解析?

    答:由 XMLMapperBuilder类来解析

    2、用什么解析?

    答:内部通过XPath来解析xml

    3、解析成什么?

    答:解析成 SqlSource

    4、解析结果如何存放?

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

    5、最终用途?

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

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

  • 相关阅读:
    《实验细节》上手使用PEFT库方法和常见出错问题
    使用Qt轻量的QTextBrowser为taskBus SDR显示丰富的图文帮助
    nvm下载npm报错
    docker运维之自定义网络配置
    Java 消息策略的实现 - Kafak 是怎么设计的
    【交叉熵损失torch.nn.CrossEntropyLoss详解-附代码实现】
    Splunk 打开 9997 port
    手机浏览器上网谁最快?手机浏览器速度测评
    使用在线白板高效进行活动策划的详细流程,用对工具效率拉满!
    目标检测的方法
  • 原文地址:https://blog.csdn.net/zhang527294844/article/details/136353315